#This program solves the Navier Stokes equation. It uses the method of
#constructed solutions to test for convergence, which should be 2nd order 

#from __future__ import division
import numpy as np
import numpy.fft as fft
from numpy import pi 
from pyfft.cl import Plan
import pyopencl as cl
import pyopencl.array as cl_array
from pyopencl.elementwise import ElementwiseKernel
import time
import sys
from pyvisfile.vtk import write_structured_grid
from pyvisfile.vtk import (
           UnstructuredGrid, DataArray,
           AppendedDataXMLGenerator,
           VTK_VERTEX, VF_LIST_OF_VECTORS, VF_LIST_OF_COMPONENTS)
from pyvisfile.vtk import (
           UnstructuredGrid, DataArray,
           AppendedDataXMLGenerator,
           VTK_TRIANGLE, VF_LIST_OF_VECTORS, VF_LIST_OF_COMPONENTS)
np.set_printoptions(threshold=sys.maxint)
from warnings import filterwarnings
filterwarnings("ignore", module="pyopencl.cache", lineno=336)
filterwarnings("ignore", module="pyopencl", lineno=163)
TIMING = 0 
WGPSIZE_1 = 8 
WGPSIZE_2 = 4
WGPSIZE_3 = 4  
b_WGPSIZE = 2 
PR_INT = 50 
#PR_INT = 1 
start_size = 6
end_size = 6 

#lifted from http://sites.google.com/site/dlampetest/python/triangulating-a-sphere-recursively 
octahedron_vertices = np.array( [ 
    [ 1.0, 0.0, 0.0], # 0 
    [-1.0, 0.0, 0.0], # 1
    [ 0.0, 1.0, 0.0], # 2 
    [ 0.0,-1.0, 0.0], # 3
    [ 0.0, 0.0, 1.0], # 4 
    [ 0.0, 0.0,-1.0]  # 5                                
    ] )
octahedron_triangles = np.array( [ 
    [ 0, 4, 2 ],
    [ 2, 4, 1 ],
    [ 1, 4, 3 ],
    [ 3, 4, 0 ],
    [ 0, 2, 5 ],
    [ 2, 1, 5 ],
    [ 1, 3, 5 ],
    [ 3, 0, 5 ]] )

def normalize_v3(arr):
    ''' Normalize a numpy array of 3 component vectors shape=(n,3) '''
    lens = np.sqrt( arr[:,0]**2 + arr[:,1]**2 + arr[:,2]**2 )
    arr[:,0] /= lens
    arr[:,1] /= lens
    arr[:,2] /= lens                
    return arr

def normalize_v3_sing(arr):
    ''' Normalize a numpy array of 3 component vectors shape=(n,3) '''
    lens = np.sqrt( arr[0]**2 + arr[1]**2 + arr[2]**2 )
    arr[0] /= lens
    arr[1] /= lens
    arr[2] /= lens                
    return arr

def divide_all( vertices, triangles ):    
    #new_triangles = []
    new_triangle_count = len( triangles ) * 4
    # Subdivide each triangle in the old approximation and normalize
    #  the new points thus generated to lie on the surface of the unit
    #  sphere.
    # Each input triangle with vertices labelled [0,1,2] as shown
    #  below will be turned into four new triangles:
    #
    #            Make new points
    #                 a = (0+2)/2
    #                 b = (0+1)/2
    #                 c = (1+2)/2
    #        1
    #       /\        Normalize a, b, c
    #      /  \
    #    b/____\ c    Construct new triangles
    #    /\    /\       t1 [0,b,a]
    #   /  \  /  \      t2 [b,1,c]
    #  /____\/____\     t3 [a,b,c]
    # 0      a     2    t4 [a,c,2]    
    for i in range(0,triangles.shape[0]):
        v0 = vertices[ triangles[i,0] ]
        v1 = vertices[ triangles[i,1] ]
        v2 = vertices[ triangles[i,2] ]
        a = ( v0+v2 ) * 0.5
        b = ( v0+v1 ) * 0.5
        c = ( v1+v2 ) * 0.5  
        normalize_v3_sing( a )
        normalize_v3_sing( b )
        normalize_v3_sing( c )
    
        #Stack the triangles together.
        if (i == 0):
            new_vertices = np.vstack( (v0,a,b,  b,c,v1,  a,c,b, a,v2,c) )
        else:
            new_vertices = np.vstack( (new_vertices,v0,a,b,  b,c,v1,  a,c,b, a,v2,c) )
        #Now our vertices are duplicated, and thus our triangle structure are unnecesarry.    

   # v0 = vertices[ triangles[:,0] ]
   # v1 = vertices[ triangles[:,1] ]
   # v2 = vertices[ triangles[:,2] ]
   # a = ( v0+v2 ) * 0.5
   # b = ( v0+v1 ) * 0.5
   # c = ( v1+v2 ) * 0.5  
   # normalize_v3( a )
   # normalize_v3( b )
   # normalize_v3( c )
   # 
   # #Stack the triangles together.
   # vertices = np.vstack( (v0,b,a,  b,v1,c,  a,b,c, a,c,v2) )
   # #Now our vertices are duplicated, and thus our triangle structure are unnecesarry.    

    return new_vertices, np.arange( len(new_vertices) ).reshape( (-1,3) )

def make_unique( vertices, triangles ):
    N_tri = triangles.shape[0] 
    N_vert = vertices.shape[0]



    i = 0
    while i < vertices.shape[0] :
        #find indices of repeat vertices
        indices = np.nonzero(np.logical_and(np.logical_and(vertices[:,0] == vertices[i,0],vertices[:,1] == vertices[i,1]),vertices[:,2] == vertices[i,2]))
        indices = indices[0]

        #replace repeats in triangles
        for j in range(0,len(indices)):  
            if (indices[j] != i):
                triangles[triangles == indices[j]] = i 

        for j in range(0,len(indices)):  
            j = len(indices)-1-j
            if (indices[j] != i):
                #delete repeat vertices
                vertices = np.delete(vertices,indices[j],0)
                triangles[triangles > indices[j]] = triangles[triangles > indices[j]] - 1 

        i = i+1

    #delete repeat triangles 
    i = 0
    while i < triangles.shape[0]:
        indices = np.nonzero(np.logical_and(np.logical_and(triangles[:,0] == triangles[i,0],triangles[:,1] == triangles[i,1]),triangles[:,2] == triangles[i,2]))
        indices = indices[0]
    
        for j in range(0,len(indices)):
            if (indices[j] != i):
                triangles = np.delete(triangles,indices[j],0)

        i = i+1
 
    return vertices, triangles

def create_unit_sphere( recursion_level=2 ):
    vertex_array, index_array = octahedron_vertices, octahedron_triangles
    for i in range( recursion_level - 1 ):
        vertex_array, index_array  = divide_all(vertex_array, index_array)

    vertex_array, index_array = make_unique(vertex_array, index_array)    

    i = 0
    #check that triangles have correct orientation
    while i < index_array.shape[0] :
        x1 = vertex_array[index_array[i,0],:]
        x2 = vertex_array[index_array[i,1],:]
        x3 = vertex_array[index_array[i,2],:]

        n = np.cross(x2-x1,x3-x1)
        n = n/np.sqrt(np.dot(n,n))

        if (np.sum(n*x1) < 0):
            print 'negative', np.sum(n*x1)

        i = i+1

    return vertex_array, index_array


def vertex_array_only_unit_sphere( recursion_level=2 ):
    vertex_array, index_array = create_unit_sphere(recursion_level)
    if recursion_level > 1:    
        return vertex_array.reshape( (-1) )
    else:
        return vertex_array[index_array].reshape( (-1) )

def spread_routine(q, firstn1, nextn1, firstn2, nextn2, firstn3, nextn3, F_1, F_2, F_3, X_1, X_2, X_3, N, dx, dtheta, f_1, f_2, f_3):
    for shift0 in range(0,4):
        for shift1 in range(0,4):
            for shift2 in range(0,4):
                spread_kernel(q, (N/4, N/4, N/4), (WGPSIZE_1, WGPSIZE_2, WGPSIZE_3), firstn1.data, nextn1.data, firstn2.data, nextn2.data, firstn3.data, nextn3.data, F_1.data, F_2.data, F_3.data, X_1.data, X_2.data, X_3.data, N, dx, dtheta, shift0, shift1, shift2, f_1.data, f_2.data, f_3.data)

def update_routine(q, firstn1, nextn1, firstn2, nextn2, firstn3, nextn3, X_1, X_2, X_3, N, dx):
    for shift0 in range(0,4):
        for shift1 in range(0,4):
            for shift2 in range(0,4):
                updaten_kernel(q, (N/4, N/4, N/4), (WGPSIZE_1, WGPSIZE_2, WGPSIZE_3), firstn1.data, nextn1.data, firstn2.data, nextn2.data, firstn3.data, nextn3.data, X_1.data, X_2.data, X_3.data, N, dx, shift0, shift1, shift2)

def calc_transf(dx):
    N = np.int(np.round(1/dx,0))
    k = np.arange(0, N/2+1)
    k = np.hstack([k, np.arange(-N/2+1, 0)])
    k1 = np.tile(k, (N, N, 1))
    k2 = np.tile(k.reshape(N,1), (N, 1, N))
    k3 = np.tile(k.reshape(N,1,1), (1, N, N))
    L_tf = -4./dx**2 * (np.sin(pi*k1/N)**2+np.sin(pi*k2/N)**2+np.sin(pi*k3/N)**2) 
    L_tf[0,0,0] = 1. #avoid dividing by zero
    return L_tf

def solve(t_step):
    global dx, dt, mu, rho, b_q, dtheta, N_teth, k_teth, dr, ds, k_area, N_tri, body_f, CT_max, k_curv
    N = np.int(np.round(1/dx,0))

    imag_gpu(u_1_gpu, u_1_tf_gpu)
    imag_gpu(u_2_gpu, u_2_tf_gpu)
    imag_gpu(u_3_gpu, u_3_tf_gpu)

    plan.execute(u_1_tf_gpu.data)
    plan.execute(u_2_tf_gpu.data)
    plan.execute(u_3_tf_gpu.data)
    
    #calc_lagF_gpu(X_1_gpu, X_2_gpu, X_3_gpu, rr_lag_gpu, ip_s_lag_gpu, im_s_lag_gpu, ds, F_1_gpu, F_2_gpu, F_3_gpu)
    zero_gpu(F_1_gpu)
    zero_gpu(F_2_gpu)
    zero_gpu(F_3_gpu)
    calc_lagF_teth_kernel(queue, (N_teth, 1), (b_WGPSIZE, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, X_1_teth_gpu.data, X_2_teth_gpu.data, X_3_teth_gpu.data, i_teth_gpu.data, k_teth, dr, F_1_gpu.data, F_2_gpu.data, F_3_gpu.data)
    #test curv kernel
    runs = 10
    diff = np.zeros((runs,1))
    zero_gpu(en_gpu)
    zero_gpu(F_1_gpu)
    zero_gpu(F_2_gpu)
    zero_gpu(F_3_gpu)
    #calc_curv_kernel(queue, (b_q, 1), (1, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, CT_gpu.data, N_tri, CT_max, F_1_gpu.data, F_2_gpu.data, F_3_gpu.data) 
    #calc_energy_area_kernel(queue, (1, 1), (1, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, A_0_gpu.data, k_area, N_tri, en_gpu.data) 
    calc_energy_curv_kernel(queue, (1, 1), (1, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, CT_gpu.data, CT_max, b_q, 0, k_curv, en_gpu.data) 
    #calc_energy_hook_kernel(queue, (1, 1), (1, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, X_ref_1_gpu.data, X_ref_2_gpu.data, X_ref_3_gpu.data, A_0_gpu.data, k_bulk, k_shear, N_tri, en_gpu.data) 
    #calc_energy_test_kernel(queue, (1, 1), (1, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, en_gpu.data) 
    #F_1_0 = F_1_gpu.get()[0]  
    en_0 = en_gpu.get()[0]
    print 'hook energy is', en_0
    #calc_lagF_area_kernel(queue, (b_q, 1), (1, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, A_0_gpu.data, CT_gpu.data, CT_max, k_area, F_1_gpu.data, F_2_gpu.data, F_3_gpu.data)
    calc_F_curv_kernel(queue, (b_q, 1), (1, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, CT_gpu.data, CT_max, 0, k_curv, F_1_gpu.data, F_2_gpu.data, F_3_gpu.data)
    #calc_lagF_hook_kernel(queue, (b_q, 1), (1, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, X_ref_1_gpu.data, X_ref_2_gpu.data, X_ref_3_gpu.data, A_0_gpu.data, CT_gpu.data, CT_max, k_bulk, k_shear, F_1_gpu.data, F_2_gpu.data, F_3_gpu.data)
    #calc_lagF_test_kernel(queue, (1, 1), (1, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, F_1_gpu.data, F_2_gpu.data, F_3_gpu.data)
    for i in range(0,runs):
        delta = 10**-i  
        add_gpu(X_1_gpu, Z_1_gpu, delta, X_1_new_gpu) 
        add_gpu(X_2_gpu, Z_2_gpu, delta, X_2_new_gpu) 
        add_gpu(X_3_gpu, Z_3_gpu, delta, X_3_new_gpu) 
        #zero_gpu(F_1_gpu)
        #zero_gpu(F_2_gpu)
        #zero_gpu(F_3_gpu)
        #calc_curv_kernel(queue, (b_q, 1), (1, 1), X_1_new_gpu.data, X_2_new_gpu.data, X_3_new_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, CT_gpu.data, N_tri, CT_max, F_1_gpu.data, F_2_gpu.data, F_3_gpu.data) 
        zero_gpu(en_gpu)
        calc_energy_curv_kernel(queue, (1, 1), (1, 1), X_1_new_gpu.data, X_2_new_gpu.data, X_3_new_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, CT_gpu.data, CT_max, b_q, 0, k_curv, en_gpu.data) 
        #calc_energy_test_kernel(queue, (1, 1), (1, 1), X_1_new_gpu.data, X_2_new_gpu.data, X_3_new_gpu.data, en_gpu.data) 
        #calc_energy_hook_kernel(queue, (1, 1), (1, 1), X_1_new_gpu.data, X_2_new_gpu.data, X_3_new_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, X_ref_1_gpu.data, X_ref_2_gpu.data, X_ref_3_gpu.data, A_0_gpu.data, k_bulk, k_shear, N_tri, en_gpu.data) 
        #print F_1_gpu.get()[0]
        #calc_energy_area_kernel(queue, (1, 1), (1, 1), X_1_new_gpu.data, X_2_new_gpu.data, X_3_new_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, A_0_gpu.data, k_area, N_tri, en_gpu.data) 
        print 'curv en is', en_gpu.get() 
        #diff[i] = en_gpu.get()[0]-en_0-delta*(np.sum(F_1_gpu.get()*Z_1)+np.sum(F_2_gpu.get()*Z_2)+np.sum(F_3_gpu.get()*Z_3)) 
        diff[i] = en_gpu.get()[0]-en_0+delta*(np.sum(F_1_gpu.get()*Z_1_gpu.get())+np.sum(F_2_gpu.get()*Z_2_gpu.get())+np.sum(F_3_gpu.get()*Z_3_gpu.get())) 
        #diff[i] = en_gpu.get()[0]-en_0
        #diff[i] = F_1_gpu.get()[0]-F_1_0-delta*(np.sum(F_11_gpu.get()*Z_1)+np.sum(F_12_gpu.get()*Z_2)+np.sum(F_13_gpu.get()*Z_3))
        print 'diff is', diff[i]

    for i in range(0,runs-1):
        print 'ratio is', diff[i+1]/diff[i]

    #test force kernel
    #runs = 10
    #diff = np.zeros((runs,1))
    #zero_gpu(en_gpu)
    #calc_energy_area_kernel(queue, (N_tri, 1), (1, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, A_0_gpu.data, k_area, N_tri, en_gpu.data) 
    #en_0 = en_gpu.get()[0]
    #calc_lagF_area_kernel(queue, (N_tri, 1), (1, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, A_0_gpu.data, k_area, N_tri, F_1_gpu.data, F_2_gpu.data, F_3_gpu.data)
    #for i in range(0,runs):
    #    delta = 10**-i  
    #    add_gpu(X_1_gpu, Z_1_gpu, delta, X_1_new_gpu) 
    #    add_gpu(X_2_gpu, Z_2_gpu, delta, X_2_new_gpu) 
    #    add_gpu(X_3_gpu, Z_3_gpu, delta, X_3_new_gpu) 
    #    zero_gpu(en_gpu)
    #    calc_energy_area_kernel(queue, (N_tri, 1), (1, 1), X_1_new_gpu.data, X_2_new_gpu.data, X_3_new_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, A_0_gpu.data, k_area, N_tri, en_gpu.data) 
    #    #print 'en is', en_gpu.get() 
    #    diff[i] = en_gpu.get()[0]-en_0+delta*(np.sum(F_1_gpu.get()*Z_1)+np.sum(F_2_gpu.get()*Z_2)+np.sum(F_3_gpu.get()*Z_3)) 
    #    print 'diff is', diff[i]

    #for i in range(0,runs-1):
    #    print 'ratio is', diff[i+1]/diff[i]

    #for i in range(0,N_tri):
    #    X_1 = X_1_gpu.get()
    #    X_2 = X_2_gpu.get()
    #    X_3 = X_3_gpu.get()
    #    X_1_new = X_1_new_gpu.get()
    #    X_2_new = X_2_new_gpu.get()
    #    X_3_new = X_3_new_gpu.get()
    #    x11 = X_1_new[TV[i,0]]
    #    x12 = X_2_new[TV[i,0]]
    #    x13 = X_3_new[TV[i,0]]
    #    x21 = X_1_new[TV[i,1]]
    #    x22 = X_2_new[TV[i,1]]
    #    x23 = X_3_new[TV[i,1]]
    #    x31 = X_1_new[TV[i,2]]
    #    x32 = X_2_new[TV[i,2]]
    #    x33 = X_3_new[TV[i,2]]
    #    b1 = x31-x11
    #    b2 = x32-x12
    #    b3 = x33-x13
    #    a1 = x21-x11
    #    a2 = x22-x12
    #    a3 = x23-x13
    #    n1 = a2*b3-a3*b2
    #    n2 = a3*b1-a1*b3
    #    n3 = a1*b2-a2*b1
    #
    #    norm = np.sqrt(n1*n1+n2*n2+n3*n3)
    #    n1 = n1/norm
    #    n2 = n2/norm
    #    n3 = n3/norm
    #
    #    a1 = x31-x21 
    #    a2 = x32-x22 
    #    a3 = x33-x23 

    #    b1 = 0.5*(n2*a3-n3*a2)
    #    b2 = 0.5*(n3*a1-n1*a3)
    #    b3 = 0.5*(n1*a2-n2*a1)

        #print (0.5*norm-A_0[i])
        #print (0.5*norm-A_0[i])
        #print (0.5*norm-A_0[i])

    #    a1 = x11-x31 
    #    a2 = x12-x32 
    #    a3 = x13-x33 

    #    b1 = 0.5*(n2*a3-n3*a2)
    #    b2 = 0.5*(n3*a1-n1*a3)
    #    b3 = 0.5*(n1*a2-n2*a1)

        #print (0.5*norm-A_0[i])*b1
        #print (0.5*norm-A_0[i])*b2
        #print (0.5*norm-A_0[i])*b3

    #    a1 = x21-x11 
    #    a2 = x22-x12 
    #    a3 = x23-x13 

    #    b1 = 0.5*(n2*a3-n3*a2)
    #    b2 = 0.5*(n3*a1-n1*a3)
    #    b3 = 0.5*(n1*a2-n2*a1)

        #print (0.5*norm-A_0[i])*b1
        #print (0.5*norm-A_0[i])*b2
        #print (0.5*norm-A_0[i])*b3

    calc_lagF_area_old_kernel(queue, (N_tri, 1), (1, 1), X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, A_0_gpu.data, k_area, N_tri, F_1_gpu.data, F_2_gpu.data, F_3_gpu.data)
    #print TV
    #print X_1_gpu.get()
    #print X_2_gpu.get()
    #print X_3_gpu.get()
    #print F_1_gpu.get()
    #print F_2_gpu.get()
    #print F_3_gpu.get()

    interp_kernel(queue, (b_q, 1), (b_WGPSIZE, 1), u_1_gpu.data, u_2_gpu.data, u_3_gpu.data, X_1_gpu.data, X_2_gpu.data, X_3_gpu.data, N, dx, U_1_gpu.data, U_2_gpu.data, U_3_gpu.data)

    add_gpu(X_1_gpu, U_1_gpu, dt, X_1_tilde_gpu)
    add_gpu(X_2_gpu, U_2_gpu, dt, X_2_tilde_gpu)
    add_gpu(X_3_gpu, U_3_gpu, dt, X_3_tilde_gpu)

    #copy_gpu(u_1_gpu,test_1_gpu) #for debugging 
    #copy_gpu(u_2_gpu,test_2_gpu) 
    #copy_gpu(u_3_gpu,test_3_gpu) 

    zero_gpu(f_1_gpu)
    zero_gpu(f_2_gpu)
    zero_gpu(f_3_gpu)
    zero_gpu(u_1_tilde_gpu)
    zero_gpu(u_2_tilde_gpu)
    zero_gpu(u_3_tilde_gpu)

    spread_routine(queue, firstn1_gpu, nextn1_gpu, firstn2_gpu, nextn2_gpu, firstn3_gpu, nextn3_gpu, F_1_gpu, F_2_gpu, F_3_gpu, X_1_gpu, X_2_gpu, X_3_gpu, N, dx, dtheta, u_1_tilde_gpu, u_2_tilde_gpu, u_3_tilde_gpu)

    add_gpu(u_1_tilde_gpu, body_gpu, body_f, u_1_tilde_gpu)

    #check power identity
    #print 'power is', (U_1_gpu.get()*F_1_gpu.get()+U_2_gpu.get()*F_2_gpu.get()+U_3_gpu.get()*F_3_gpu.get()).sum()*dtheta-(u_1_tilde_gpu.get()*u_1_gpu.get()+u_2_tilde_gpu.get()*u_2_gpu.get()+u_3_tilde_gpu.get()*u_3_gpu.get()).sum()*dx*dx*dx
    #print 'power is', (U_1_gpu.get()*F_1_gpu.get()+U_2_gpu.get()*F_2_gpu.get()).sum()*dtheta-(u_1_tilde_gpu.get()*u_1_gpu.get()+u_2_tilde_gpu.get()*u_2_gpu.get()).sum()*dx*dx*dx
    #check momentum conservation
    print 'mom1 is', u_1_gpu.get().sum()*dx*dx*dx
    print 'mom2 is', u_2_gpu.get().sum()*dx*dx*dx
    print 'mom3 is', u_3_gpu.get().sum()*dx*dx*dx
    #print (U_1_gpu.get()*F_1_gpu.get()+U_2_gpu.get()*F_2_gpu.get()).sum()*dtheta

    add_gpu(f_1_gpu, u_1_tilde_gpu, 1, f_1_gpu) 
    add_gpu(f_2_gpu, u_2_tilde_gpu, 1, f_2_gpu) 
    add_gpu(f_3_gpu, u_3_tilde_gpu, 1, f_3_gpu) 

    ss_conv_kernel(queue, (N,N,N), (WGPSIZE_1, WGPSIZE_2, WGPSIZE_3), u_1_gpu.data, u_2_gpu.data, u_3_gpu.data, dx, N, u_1_tilde_gpu.data, u_2_tilde_gpu.data, u_3_tilde_gpu.data)
    #zero_gpu(u_1_tilde_gpu) #turn off convection
    #zero_gpu(u_2_tilde_gpu)
    #zero_gpu(u_3_tilde_gpu)

    add_gpu(f_1_gpu, u_1_tilde_gpu, -rho, f_1_gpu)
    add_gpu(f_2_gpu, u_2_tilde_gpu, -rho, f_2_gpu)
    add_gpu(f_3_gpu, u_3_tilde_gpu, -rho, f_3_gpu)

    copy_gpu(f_1_gpu, u_1_tilde_gpu)
    copy_gpu(f_2_gpu, u_2_tilde_gpu)
    copy_gpu(f_3_gpu, u_3_tilde_gpu)
    ##########################################################solve for u_tilde
    div_kernel(queue, (N,N,N), (WGPSIZE_1, WGPSIZE_2, WGPSIZE_3), f_1_gpu.data, f_2_gpu.data, f_3_gpu.data, dx, N, p_gpu.data)
    imag_gpu(p_gpu, p_tf_gpu)
    plan.execute(p_tf_gpu.data)

    L_adj_2_kernel(queue, (1,1), (1,1), L_tf_gpu.data)
    calc_p_gpu(p_tf_gpu, L_tf_gpu, p_tf_gpu)
    p_filt_kernel(queue, (1,1), (1,1), p_tf_gpu.data)
    plan.execute(p_tf_gpu.data, inverse=True)
    real_gpu(p_tf_gpu, p_gpu)

    grad_kernel(queue, (N,N,N), (WGPSIZE_1, WGPSIZE_2, WGPSIZE_3), p_gpu.data, dx, N, u_1_gpu.data, u_2_gpu.data, u_3_gpu.data)

    add_gpu(f_1_gpu, u_1_gpu, -1, f_1_gpu)
    add_gpu(f_2_gpu, u_2_gpu, -1, f_2_gpu)
    add_gpu(f_3_gpu, u_3_gpu, -1, f_3_gpu)

    imag_gpu(f_1_gpu, f_1_tf_gpu)
    imag_gpu(f_2_gpu, f_2_tf_gpu)
    imag_gpu(f_3_gpu, f_3_tf_gpu)

    plan.execute(f_1_tf_gpu.data)
    plan.execute(f_2_tf_gpu.data)
    plan.execute(f_3_tf_gpu.data)

    L_adj_1_kernel(queue, (1,1), (1,1), L_tf_gpu.data)
    solve_kernel(queue, (N,N,N), (WGPSIZE_1, WGPSIZE_2, WGPSIZE_3), u_1_tf_gpu.data, u_2_tf_gpu.data, u_3_tf_gpu.data, L_tf_gpu.data, f_1_tf_gpu.data, f_2_tf_gpu.data, f_3_tf_gpu.data, dt, rho, mu, N, f_1_tf_gpu.data, f_2_tf_gpu.data, f_3_tf_gpu.data)

    nyq_filt_kernel(queue, (N,N), (WGPSIZE_1, WGPSIZE_2), f_1_tf_gpu.data, N)
    nyq_filt_kernel(queue, (N,N), (WGPSIZE_1, WGPSIZE_2), f_2_tf_gpu.data, N)
    nyq_filt_kernel(queue, (N,N), (WGPSIZE_1, WGPSIZE_2), f_3_tf_gpu.data, N)

    zero_gpu(f_1_gpu)
    zero_gpu(f_2_gpu)
    zero_gpu(f_3_gpu)

    add_gpu(f_1_gpu, u_1_tilde_gpu, 0.5, f_1_gpu)
    add_gpu(f_2_gpu, u_2_tilde_gpu, 0.5, f_2_gpu)
    add_gpu(f_3_gpu, u_3_tilde_gpu, 0.5, f_3_gpu)

    plan.execute(f_1_tf_gpu.data, inverse=True)
    plan.execute(f_2_tf_gpu.data, inverse=True)
    plan.execute(f_3_tf_gpu.data, inverse=True)
    
    real_gpu(f_1_tf_gpu, u_1_tilde_gpu)
    real_gpu(f_2_tf_gpu, u_2_tilde_gpu)
    real_gpu(f_3_tf_gpu, u_3_tilde_gpu)
    ############################################################

    ############################################################solve for u_soln
    #calc_lagF_gpu(X_1_tilde_gpu, X_2_tilde_gpu, X_3_tilde_gpu, rr_lag_gpu, ip_s_lag_gpu, im_s_lag_gpu, ds, F_1_gpu, F_2_gpu, F_3_gpu)
    zero_gpu(F_1_gpu)
    zero_gpu(F_2_gpu)
    zero_gpu(F_3_gpu)
    calc_lagF_teth_kernel(queue, (N_teth, 1), (b_WGPSIZE, 1), X_1_tilde_gpu.data, X_2_tilde_gpu.data, X_3_tilde_gpu.data, X_1_teth_gpu.data, X_2_teth_gpu.data, X_3_teth_gpu.data, i_teth_gpu.data, k_teth, dr, F_1_gpu.data, F_2_gpu.data, F_3_gpu.data)
    calc_lagF_area_old_kernel(queue, (N_tri, 1), (1, 1), X_1_tilde_gpu.data, X_2_tilde_gpu.data, X_3_tilde_gpu.data, TV_1_gpu.data, TV_2_gpu.data, TV_3_gpu.data, A_0_gpu.data, k_area, N_tri, F_1_gpu.data, F_2_gpu.data, F_3_gpu.data)

    update_routine(queue, firstn1_gpu, nextn1_gpu, firstn2_gpu, nextn2_gpu, firstn3_gpu, nextn3_gpu, X_1_tilde_gpu, X_2_tilde_gpu, X_3_tilde_gpu, N, dx)

    zero_gpu(u_1_gpu)
    zero_gpu(u_2_gpu)
    zero_gpu(u_3_gpu)

    spread_routine(queue, firstn1_gpu, nextn1_gpu, firstn2_gpu, nextn2_gpu, firstn3_gpu, nextn3_gpu, F_1_gpu, F_2_gpu, F_3_gpu, X_1_tilde_gpu, X_2_tilde_gpu, X_3_tilde_gpu, N, dx, dtheta, u_1_gpu, u_2_gpu, u_3_gpu)

    add_gpu(u_1_gpu, body_gpu, body_f, u_1_gpu)

    add_gpu(f_1_gpu, u_1_gpu, 0.5, f_1_gpu)
    add_gpu(f_2_gpu, u_2_gpu, 0.5, f_2_gpu)
    add_gpu(f_3_gpu, u_3_gpu, 0.5, f_3_gpu)

    ss_conv_kernel(queue, (N,N,N), (WGPSIZE_1, WGPSIZE_2, WGPSIZE_3), u_1_tilde_gpu.data, u_2_tilde_gpu.data, u_3_tilde_gpu.data, dx, N, u_1_gpu.data, u_2_gpu.data, u_3_gpu.data)
    #zero_gpu(u_1_gpu) #turn off convection
    #zero_gpu(u_2_gpu)
    #zero_gpu(u_3_gpu)

    add_gpu(f_1_gpu, u_1_gpu, -rho*0.5, f_1_gpu)
    add_gpu(f_2_gpu, u_2_gpu, -rho*0.5, f_2_gpu)
    add_gpu(f_3_gpu, u_3_gpu, -rho*0.5, f_3_gpu)

    div_kernel(queue, (N,N,N), (WGPSIZE_1, WGPSIZE_2, WGPSIZE_3), f_1_gpu.data, f_2_gpu.data, f_3_gpu.data, dx, N, p_gpu.data)
    imag_gpu(p_gpu, p_tf_gpu)
    plan.execute(p_tf_gpu.data)

    L_adj_2_kernel(queue, (1,1), (1,1), L_tf_gpu.data)
    calc_p_gpu(p_tf_gpu, L_tf_gpu, p_tf_gpu)
    p_filt_kernel(queue, (1,1), (1,1), p_tf_gpu.data)
    plan.execute(p_tf_gpu.data, inverse=True)
    real_gpu(p_tf_gpu, p_gpu)

    grad_kernel(queue, (N,N,N), (WGPSIZE_1, WGPSIZE_2, WGPSIZE_3), p_gpu.data, dx, N, u_1_gpu.data, u_2_gpu.data, u_3_gpu.data)

    add_gpu(f_1_gpu, u_1_gpu, -1, f_1_gpu)
    add_gpu(f_2_gpu, u_2_gpu, -1, f_2_gpu)
    add_gpu(f_3_gpu, u_3_gpu, -1, f_3_gpu)

    imag_gpu(f_1_gpu, f_1_tf_gpu)
    imag_gpu(f_2_gpu, f_2_tf_gpu)
    imag_gpu(f_3_gpu, f_3_tf_gpu)

    plan.execute(f_1_tf_gpu.data)
    plan.execute(f_2_tf_gpu.data)
    plan.execute(f_3_tf_gpu.data)

    L_adj_1_kernel(queue, (1,1), (1,1), L_tf_gpu.data)
    solve_kernel(queue, (N,N,N), (WGPSIZE_1, WGPSIZE_2, WGPSIZE_3), u_1_tf_gpu.data, u_2_tf_gpu.data, u_3_tf_gpu.data, L_tf_gpu.data, f_1_tf_gpu.data, f_2_tf_gpu.data, f_3_tf_gpu.data, dt, rho, mu, N, f_1_tf_gpu.data, f_2_tf_gpu.data, f_3_tf_gpu.data)

    nyq_filt_kernel(queue, (N,N), (WGPSIZE_1, WGPSIZE_2), f_1_tf_gpu.data, N)
    nyq_filt_kernel(queue, (N,N), (WGPSIZE_1, WGPSIZE_2), f_2_tf_gpu.data, N)
    nyq_filt_kernel(queue, (N,N), (WGPSIZE_1, WGPSIZE_2), f_3_tf_gpu.data, N)

    plan.execute(f_1_tf_gpu.data, inverse=True)
    plan.execute(f_2_tf_gpu.data, inverse=True)
    plan.execute(f_3_tf_gpu.data, inverse=True)
    
    real_gpu(f_1_tf_gpu, u_1_gpu)
    real_gpu(f_2_tf_gpu, u_2_gpu)
    real_gpu(f_3_tf_gpu, u_3_gpu)

    interp_kernel(queue, (b_q, 1), (b_WGPSIZE, 1), u_1_gpu.data, u_2_gpu.data, u_3_gpu.data, X_1_tilde_gpu.data, X_2_tilde_gpu.data, X_3_tilde_gpu.data, N, dx, F_1_gpu.data, F_2_gpu.data, F_3_gpu.data)
    add_gpu(U_1_gpu, F_1_gpu, 1, U_1_gpu)
    add_gpu(U_2_gpu, F_2_gpu, 1, U_2_gpu)
    add_gpu(U_3_gpu, F_3_gpu, 1, U_3_gpu)
    add_gpu(X_1_gpu, U_1_gpu, dt/2., X_1_gpu)
    add_gpu(X_2_gpu, U_2_gpu, dt/2., X_2_gpu)
    add_gpu(X_3_gpu, U_3_gpu, dt/2., X_3_gpu)

    update_routine(queue, firstn1_gpu, nextn1_gpu, firstn2_gpu, nextn2_gpu, firstn3_gpu, nextn3_gpu, X_1_gpu, X_2_gpu, X_3_gpu, N, dx)
    ##############################################################
    return

def err(u_1, u_2, u_3, u_1_o, u_2_o, u_3_o):
    global dx
    NN_o = u_1_o.shape[0]
    errinf1 = 0.
    errinf2 = 0.
    errinf3 = 0.
    err11 = 0.
    err12 = 0.
    err13 = 0.
    err21 = 0.
    err22 = 0.
    err23 = 0.

    for i in range(0,NN_o):
        for j in range(0,NN_o):
            for k in range(0,NN_o):
                if (np.abs(u_1_o[k,i,j]-0.25*(u_1[2*k,2*i,2*j]+u_1[2*k,2*i+1,2*j]+u_1[2*k+1,2*i,2*j]+u_1[2*k+1,2*i+1,2*j]))>errinf1):
                    errinf1 = np.abs(u_1_o[k,i,j]-0.25*(u_1[2*k,2*i,2*j]+u_1[2*k,2*i+1,2*j]+u_1[2*k+1,2*i,2*j]+u_1[2*k+1,2*i+1,2*j])) 
                if (np.abs(u_2_o[k,i,j]-0.25*(u_2[2*k,2*i,2*j]+u_2[2*k,2*i,2*j+1]+u_2[2*k+1,2*i,2*j]+u_2[2*k+1,2*i,2*j+1]))>errinf2):
                    errinf2 = np.abs(u_2_o[k,i,j]-0.25*(u_2[2*k,2*i,2*j]+u_2[2*k,2*i,2*j+1]+u_2[2*k+1,2*i,2*j]+u_2[2*k+1,2*i,2*j+1])) 
                if (np.abs(u_3_o[k,i,j]-0.25*(u_3[2*k,2*i,2*j]+u_3[2*k,2*i+1,2*j]+u_3[2*k,2*i,2*j+1]+u_3[2*k,2*i+1,2*j+1]))>errinf3):
                    errinf3 = np.abs(u_3_o[k,i,j]-0.25*(u_3[2*k,2*i,2*j]+u_3[2*k,2*i+1,2*j]+u_3[2*k,2*i,2*j+1]+u_3[2*k,2*i+1,2*j+1])) 
                err21 += np.abs(u_1_o[k,i,j]-0.25*(u_1[2*k,2*i,2*j]+u_1[2*k,2*i+1,2*j]+u_1[2*k+1,2*i,2*j]+u_1[2*k+1,2*i+1,2*j]))**2 
                err22 += np.abs(u_2_o[k,i,j]-0.25*(u_2[2*k,2*i,2*j]+u_2[2*k,2*i,2*j+1]+u_2[2*k+1,2*i,2*j]+u_2[2*k+1,2*i,2*j+1]))**2 
                err23 += np.abs(u_3_o[k,i,j]-0.25*(u_3[2*k,2*i,2*j]+u_3[2*k,2*i+1,2*j]+u_3[2*k,2*i,2*j+1]+u_3[2*k,2*i+1,2*j+1]))**2 
                err11 += np.abs(u_1_o[k,i,j]-0.25*(u_1[2*k,2*i,2*j]+u_1[2*k,2*i+1,2*j]+u_1[2*k+1,2*i,2*j]+u_1[2*k+1,2*i+1,2*j])) 
                err12 += np.abs(u_2_o[k,i,j]-0.25*(u_2[2*k,2*i,2*j]+u_2[2*k,2*i,2*j+1]+u_2[2*k+1,2*i,2*j]+u_2[2*k+1,2*i,2*j+1])) 
                err13 += np.abs(u_3_o[k,i,j]-0.25*(u_3[2*k,2*i,2*j]+u_3[2*k,2*i+1,2*j]+u_3[2*k,2*i,2*j+1]+u_3[2*k,2*i+1,2*j+1])) 

    err21 = np.sqrt(err21*dx**3/8)
    err22 = np.sqrt(err22*dx**3/8)
    err23 = np.sqrt(err23*dx**3/8)
    err11 = (dx**3/8)*err11
    err12 = (dx**3/8)*err12
    err13 = (dx**3/8)*err13

    return errinf1, errinf2, errinf3, err11, err12, err13, err21, err22, err23 

def err_ex(clock_max, u_1, u_2, u_3):
    global dx, dt
    x_stag = np.arange(-0.5, 0.5, dx)
    xx_1_stag = np.tile(x_stag, (N, N, 1))
    xx_2_stag = np.tile(x_stag.reshape(N,1), (N, 1, N))
    xx_3_stag = np.tile(x_stag.reshape(N,1,1), (1, N, N))

    x_c = np.arange(-0.5+dx/2, 0.5+dx/2, dx)
    xx_1_c = np.tile(x_c, (N, N, 1))
    xx_2_c = np.tile(x_c.reshape(N,1), (N, 1, N))
    xx_3_c = np.tile(x_c.reshape(N,1,1), (1, N, N))
    
    u_1_ex = 2*np.cos(2*pi*xx_1_stag)*np.sin(4*pi*xx_2_c)*np.sin(clock_max*dt)*np.sin(2*pi*xx_3_c)
    u_2_ex = -np.sin(2*pi*xx_1_c)*np.cos(4*pi*xx_2_stag)*np.sin(clock_max*dt)*np.sin(2*pi*xx_3_c)
    u_3_ex = np.cos(2*pi*xx_1_c)*np.sin(4*pi*xx_2_c)*np.cos(clock_max*dt)

    errinf1 = np.abs(u_1-u_1_ex).max()
    errinf2 = np.abs(u_2-u_2_ex).max()
    errinf3 = np.abs(u_3-u_3_ex).max()
    err11 = np.sum(np.abs(u_1-u_1_ex))*dx**3
    err12 = np.sum(np.abs(u_2-u_2_ex))*dx**3
    err13 = np.sum(np.abs(u_3-u_3_ex))*dx**3
    err21 = np.sqrt(np.sum(np.abs(u_1-u_1_ex)**2*dx**3))
    err22 = np.sqrt(np.sum(np.abs(u_2-u_2_ex)**2*dx**3))
    err23 = np.sqrt(np.sum(np.abs(u_3-u_3_ex)**2*dx**3))

    return errinf1, errinf2, errinf3, err11, err12, err13, err21, err22, err23

ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)

calc_lagF_gpu = ElementwiseKernel(ctx,
	"float *X_1, float *X_2, float *X_3,"
	"float *rr_lag, unsigned *ip_s_lag, unsigned *im_s_lag, " 
	"float ds, "
	"float *F_1, float *F_2, float *F_3",
	#"F_1[i] = 1./(ds*ds)*(1.+sin(2.*pi*rr_lag[i]-pi/2.))"
	#   "*(X_1[ip_s_lag[i]]-2.*X_1[i]+X_1[im_s_lag[i]]); "
	#"F_2[i] = 1./(ds*ds)*(1.+sin(2.*pi*rr_lag[i]-pi/2.))"
	#   "*(X_2[ip_s_lag[i]]-2.*X_2[i]+X_2[im_s_lag[i]]);"
	#"F_3[i] = 1./(ds*ds)*(1.+sin(2.*pi*rr_lag[i]-pi/2.))"
	#   "*(X_3[ip_s_lag[i]]-2.*X_3[i]+X_3[im_s_lag[i]])",
	#"F_1[i] = 1./(2*ds)"
	#   "*(X_1[ip_s_lag[i]]-X_1[im_s_lag[i]]); "
	#"F_2[i] = 1./(2*ds)"
	#   "*(X_2[ip_s_lag[i]]-X_2[im_s_lag[i]]);"
	#"F_3[i] = 1./(2*ds)"
	#   "*(X_3[ip_s_lag[i]]-X_3[im_s_lag[i]])",
	#"F_1[i] = 1./(ds*ds)*(X_1[ip_s_lag[i]]-2.*X_1[i]+X_1[im_s_lag[i]]); "
	#"F_2[i] = 1./(ds*ds)*(X_2[ip_s_lag[i]]-2.*X_2[i]+X_2[im_s_lag[i]]) ",
        "F_1[i] = 0.;"
        "F_2[i] = 0.;"
        "F_3[i] = 0.",
	"calc_lagF_gpu",
	preamble="""
	#define pi (float)3.141592653589793
	""")

calc_f_gpu = ElementwiseKernel(ctx,
        "float t, float dx, float mu, float rho, "
        "float *xx_1_stag, float *xx_2_stag, float *xx_3_stag,"
        "float *xx_1_c, float *xx_2_c, float *xx_3_c,"
        "float *f_1, float *f_2, float *f_3",
        "f_1[i] = rho*2*cos(2*pi*xx_1_stag[i])*sin(4*pi*xx_2_c[i])*sin(2*pi*xx_3_c[i])*cos(t)"
           "+2*pi*cos(2*pi*xx_1_stag[i])*sin(2*pi*xx_2_c[i])*cos(2*pi*xx_3_c[i])*cos(t)"
           "+mu*48*pi*pi*cos(2*pi*xx_1_stag[i])*sin(4*pi*xx_2_c[i])*sin(2*pi*xx_3_c[i])*sin(t)"
           "-rho*4*pi*sin(t)*sin(t)*sin(4*pi*xx_1_stag[i])*sin(2*pi*xx_3_c[i])*sin(2*pi*xx_3_c[i])"
           "+rho*4*pi*sin(t)*cos(t)*cos(2*pi*xx_1_stag[i])*cos(2*pi*xx_1_stag[i])*sin(4*pi*xx_2_c[i])"
           "*sin(4*pi*xx_2_c[i])*cos(2*pi*xx_3_c[i]);"
        "f_2[i] = -rho*sin(2*pi*xx_1_c[i])*cos(4*pi*xx_2_stag[i])*sin(2*pi*xx_3_c[i])*cos(t)"
           "+2*pi*sin(2*pi*xx_1_c[i])*cos(2*pi*xx_2_stag[i])*cos(2*pi*xx_3_c[i])*cos(t)"
           "-mu*24*pi*pi*sin(2*pi*xx_1_c[i])*cos(4*pi*xx_2_stag[i])*sin(2*pi*xx_3_c[i])*sin(t)"
           "-rho*2*pi*sin(t)*sin(t)*sin(8*pi*xx_2_stag[i])*sin(2*pi*xx_3_c[i])*sin(2*pi*xx_3_c[i])"
           "-rho*0.5*pi*sin(t)*cos(t)*sin(4*pi*xx_1_c[i])*sin(8*pi*xx_2_stag[i])"
           "*cos(2*pi*xx_3_c[i]);"
        "f_3[i] = -rho*cos(2*pi*xx_1_c[i])*sin(4*pi*xx_2_c[i])*sin(t)"
           "-2*pi*sin(2*pi*xx_1_c[i])*sin(2*pi*xx_2_c[i])*sin(2*pi*xx_3_stag[i])*cos(t)"
           "+mu*20*pi*pi*cos(2*pi*xx_1_c[i])*sin(4*pi*xx_2_c[i])*cos(t)"
           "-rho*2*pi*cos(t)*sin(t)*sin(4*pi*xx_1_c[i])*sin(2*pi*xx_3_stag[i])",
        "calc_f_gpu",
        preamble="""
        #define pi (float)3.141592653589793
        """)

complex_mult_gpu = ElementwiseKernel(ctx,
	"float2 *u_1, float2 *u_2, float2 *f",
	"f[i] = complex_mul(u_1[i], u_2[i])",
	"complex_mult_gpu",
	preamble="""
	#define complex_ctr(x, y) (float2)(x, y)
	#define complex_mul(a, b) complex_ctr(-(a).y*(b).y+(a).x*(b).x, (a).y*(b).x+(a).x*(b).y)
	""")

mult_gpu = ElementwiseKernel(ctx,
	"float *u_1, float *u_2, float *f",
	"f[i] = u_1[i]*u_2[i]",
	"mult_gpu")

add_gpu = ElementwiseKernel(ctx,
	"float *u_1, float *u_2, float a, float *f",
	"f[i] = u_1[i]+a*u_2[i]",
	"add_gpu")
    
copy_gpu = ElementwiseKernel(ctx,
	"float *u, float *f",
	"f[i] = u[i]",
	"copy_gpu")

scale_gpu = ElementwiseKernel(ctx,
	"float *u, float a, float *f",
	"f[i] = a*u[i]",
	"scale_gpu")

real_gpu = ElementwiseKernel(ctx,
	"float2 *x, float *z",
	"z[i] = x[i].x",
	"real_gpu")

imag_gpu = ElementwiseKernel(ctx,
	"float *x, float2 *z",
	"z[i].x = x[i];"
	"z[i].y = 0",
	"imag_gpu")

zero_gpu = ElementwiseKernel(ctx,
	"float *x",
	"x[i] = 0",
	"zero_gpu")
 
null_imag_gpu = ElementwiseKernel(ctx,
	"float2 *x, float2 *z",
	"z[i].x = x[i].x;"
	"z[i].y = 0",
	"null_imag_gpu")

calc_p_gpu = ElementwiseKernel(ctx,
	"float2 *w_tf, float2 *L_tf, float2 *p_tf",
	"p_tf[i] = complex_div(w_tf[i], L_tf[i])",
	"calc_p_gpu",
	preamble="""
	#define complex_ctr(x, y) (float2)(x, y)
	#define complex_div(a, b) 1/((b).x*(b).x+(b).y*(b).y)*complex_ctr((a).y*(b).y+(a).x*(b).x,(a).y*(b).x-(a).x*(b).y)
	""")

solve_prg = cl.Program(ctx, """
    //#pragma OPENCL EXTENSION cl_amd_printf : enable
    #define complex_ctr(x, y) (float2)(x, y)
    #define complex_mul(a, b) complex_ctr(-(a).y*(b).y+(a).x*(b).x, (a).y*(b).x+(a).x*(b).y)
    #define complex_div(a, b) 1/((b).x*(b).x+(b).y*(b).y)*complex_ctr((a).y*(b).y+(a).x*(b).x,(a).y*(b).x-(a).x*(b).y)
    __kernel void solve(__global const float2 *u_1_tf, __global const float2 *u_2_tf, 
    __global const float2 *u_3_tf, __global const float2 *L_tf,
    __global const float2 *f_1_tf, __global const float2 *f_2_tf, 
    __global const float2 *f_3_tf, const float dt, 
    const float rho, const float mu, const unsigned N,
    __global float2 *u_1_tf_tilde, __global float2 *u_2_tf_tilde, __global float2 *u_3_tf_tilde)
    {
      unsigned i = get_global_id(0);
      unsigned j = get_global_id(1);
      unsigned k = get_global_id(2);
      unsigned base = i + N*j + N*N*k;
      float2 m;
      m.x = 1.0+mu*dt/(2.0*rho)*L_tf[base].x; 
      m.y = mu*dt/(2.0*rho)*L_tf[base].y; 
      float2 rhs_1 = complex_mul(m, u_1_tf[base])+dt/rho*f_1_tf[base];
      float2 rhs_2 = complex_mul(m, u_2_tf[base])+dt/rho*f_2_tf[base];
      float2 rhs_3 = complex_mul(m, u_3_tf[base])+dt/rho*f_3_tf[base];
      float2 lhs;
      lhs.x = 1.0-mu*dt/(2.0*rho)*L_tf[base].x;
      lhs.y = -mu*dt/(2.0*rho)*L_tf[base].y;
      u_1_tf_tilde[base] = complex_div(rhs_1, lhs);
      u_2_tf_tilde[base] = complex_div(rhs_2, lhs);
      u_3_tf_tilde[base] = complex_div(rhs_3, lhs);
    }
    """).build()

prg = cl.Program(ctx, """
    //#pragma OPENCL EXTENSION cl_amd_printf : enable
    __kernel void p_filt(__global float2 *u)
    {
      u[0].x = 0.0;
      u[0].y = 0.0;
    }
    __kernel void L_adj_1(__global float2 *L_tf)
    {
      L_tf[0].x = 0.0;
      L_tf[0].y = 0.0;
    }
    __kernel void L_adj_2(__global float2 *L_tf)
    {
      L_tf[0].x = 1.0;
      L_tf[0].y = 0.0;
    }
    __kernel void nyq_filt(__global float2 *u, const unsigned N)
    {
      unsigned i = get_global_id(0);
      unsigned j = get_global_id(1);
      unsigned base = N/2 + N*i + N*N*j; 
      unsigned base1 = i + N*N/2 + N*N*j; 
      unsigned base2 = i + N*j + N*N*N/2; 
   
      u[base].x = 0.0;
      u[base].y = 0.0;
      u[base1].x = 0.0;
      u[base1].y = 0.0;
      u[base2].x = 0.0;
      u[base2].y = 0.0;
    }
    __kernel void div(__global const float *u_1,
    __global const float *u_2, __global const float *u_3, 
    const float dx, const unsigned N, __global float *f)
    {
      unsigned i = get_global_id(0);
      unsigned j = get_global_id(1);
      unsigned k = get_global_id(2);
      //f[i,j] = 1/dx*(u_1[i_2[i,j],ip_1[i,j]]-u_1[i,j]+u_2[ip_2[i,j],i_1[i,j]]-u_2[i,j];
      unsigned base = i + N*j + N*N*k;
      unsigned base1 = (i+1 & N-1)+N*j + N*N*k;
      unsigned base2 = i+N*(j+1 & N-1) + N*N*k;
      unsigned base3 = i + N*j + N*N*(k+1 & N-1);
      f[base] = 1/dx*(u_1[base1]-u_1[base]+u_2[base2]-u_2[base]+u_3[base3]-u_3[base]);
    }
    __kernel void grad(__global const float *phi,
    const float dx, const unsigned N,
    __global float *g_1, __global float *g_2, __global float *g_3)
    {
      unsigned i = get_global_id(0);
      unsigned j = get_global_id(1);
      unsigned k = get_global_id(2);
      //grad_1 = 1/dx*(phi[i_2,i_1]-phi[i_2,im_1])
      //grad_2 = 1/dx*(phi[i_2,i_1]-phi[im_2,i_1])
      unsigned base = i + N*j + N*N*k;
      unsigned base1 = (i-1 & N-1)+N*j + N*N*k;
      unsigned base2 = i+N*(j-1 & N-1) + N*N*k;
      unsigned base3 = i + N*j + N*N*(k-1 & N-1);
      g_1[base] = 1/dx*(phi[base]-phi[base1]);
      g_2[base] = 1/dx*(phi[base]-phi[base2]);
      g_3[base] = 1/dx*(phi[base]-phi[base3]);
    }
    __kernel void ss_conv(__global const float *u_1,
    __global const float *u_2, __global const float *u_3,
    const float dx, const unsigned N,
    __global float *S_1, __global float *S_2, __global float *S_3)
    {
      unsigned i = get_global_id(0);
      unsigned j = get_global_id(1);
      unsigned k = get_global_id(2);
      //Compute S = 0.5*(div(UU) + (U*grad)U).
      unsigned base = i+N*j+N*N*k;
      unsigned base1 = (i-1 & N-1)+N*j+N*N*k;
      unsigned base2 = (i+1 & N-1)+N*j+N*N*k;
      unsigned base3 = i+N*(j-1 & N-1)+N*N*k;
      unsigned base4 = i+N*(j+1 & N-1)+N*N*k;
      unsigned base5 = (i-1 & N-1)+N*(j+1 & N-1)+N*N*k;
      unsigned base6 = (i+1 & N-1)+N*(j-1 & N-1)+N*N*k;
      unsigned base7 = i+N*j+N*N*(k-1 & N-1);
      unsigned base8 = i+N*j+N*N*(k+1 & N-1);
      unsigned base9 = (i-1 & N-1)+N*j+N*N*(k+1 & N-1);
      unsigned base10 = i+N*(j-1 & N-1)+N*N*(k+1 & N-1);
      unsigned base11 = (i+1 & N-1)+N*j+N*N*(k-1 & N-1);
      unsigned base12 = i+N*(j+1 & N-1)+N*N*(k-1 & N-1);
      float D_x, D_y, D_z, A_x, A_y, A_z, D, A;
      D_x = (0.25/dx)*(
          (u_1[base2]+u_1[base])*(u_1[base2]+u_1[base]) -
          (u_1[base]+u_1[base1])*(u_1[base]+u_1[base1]));
      D_y = (0.25/dx)*(
          (u_2[base4]+u_2[base5])*(u_1[base4]+u_1[base]) -
          (u_2[base]+u_2[base1])*(u_1[base]+u_1[base3]));
      D_z = (0.25/dx)*(
          (u_3[base8]+u_3[base9])*(u_1[base8]+u_1[base]) -
          (u_3[base]+u_3[base1])*(u_1[base]+u_1[base7]));
      D = D_x + D_y + D_z;
      A_x =  (0.25/dx)*(
          (u_1[base2]+u_1[base])*(u_1[base2]-u_1[base]) +
          (u_1[base]+u_1[base1])*(u_1[base]-u_1[base1]));
      A_y = (0.25/dx)*(
            (u_2[base4]+u_2[base5])*(u_1[base4]-u_1[base]) +
            (u_2[base]+u_2[base1])*(u_1[base]-u_1[base3]));
      A_z = (0.25/dx)*(
            (u_3[base8]+u_3[base9])*(u_1[base8]-u_1[base]) +
            (u_3[base]+u_3[base1])*(u_1[base]-u_1[base7]));
      A = A_x + A_y + A_z;
      S_1[base] = 0.5*(D+A);
      D_x = (0.25/dx)*(
          (u_1[base2]+u_1[base6])*(u_2[base2]+u_2[base]) -
          (u_1[base]+u_1[base3])*(u_2[base]+u_2[base1]));
      D_y = (0.25/dx)*(
          (u_2[base4]+u_2[base])*(u_2[base4]+u_2[base]) -
          (u_2[base]+u_2[base3])*(u_2[base]+u_2[base3]));
      D_z = (0.25/dx)*(
          (u_3[base8]+u_3[base10])*(u_2[base8]+u_2[base]) -
          (u_3[base]+u_3[base3])*(u_2[base]+u_2[base7]));
      D = D_x + D_y + D_z;
      A_x =  (0.25/dx)*(
          (u_1[base2]+u_1[base6])*(u_2[base2]-u_2[base]) +
          (u_1[base]+u_1[base3])*(u_2[base]-u_2[base1]));
      A_y = (0.25/dx)*(
            (u_2[base4]+u_2[base])*(u_2[base4]-u_2[base]) +
            (u_2[base]+u_2[base3])*(u_2[base]-u_2[base3]));
      A_z = (0.25/dx)*(
            (u_3[base8]+u_3[base10])*(u_2[base8]-u_2[base]) +
            (u_3[base]+u_3[base3])*(u_2[base]-u_2[base7]));
      A = A_x + A_y + A_z;
      S_2[base] = 0.5*(D+A);
      D_x = (0.25/dx)*(
          (u_1[base2]+u_1[base11])*(u_3[base2]+u_3[base]) -
          (u_1[base]+u_1[base7])*(u_3[base]+u_3[base1]));
      D_y = (0.25/dx)*(
          (u_2[base4]+u_2[base12])*(u_3[base4]+u_3[base]) -
          (u_2[base]+u_2[base7])*(u_3[base]+u_3[base3]));
      D_z = (0.25/dx)*(
          (u_3[base8]+u_3[base])*(u_3[base8]+u_3[base]) -
          (u_3[base]+u_3[base7])*(u_3[base]+u_3[base7]));
      D = D_x + D_y + D_z;
      A_x =  (0.25/dx)*(
          (u_1[base2]+u_1[base11])*(u_3[base2]-u_3[base]) +
          (u_1[base]+u_1[base7])*(u_3[base]-u_3[base1]));
      A_y = (0.25/dx)*(
            (u_2[base4]+u_2[base12])*(u_3[base4]-u_3[base]) +
            (u_2[base]+u_2[base7])*(u_3[base]-u_3[base3]));
      A_z = (0.25/dx)*(
            (u_3[base8]+u_3[base])*(u_3[base8]-u_3[base]) +
            (u_3[base]+u_3[base7])*(u_3[base]-u_3[base7]));
      A = A_x + A_y + A_z;
      S_3[base] = 0.5*(D+A);
    }
    """).build()

ib_prg = cl.Program(ctx, """
    __kernel void spread(__global const int *firstn1, __global const int *nextn1, __global const int *firstn2, __global const int *nextn2, __global const int *firstn3, __global const int *nextn3, __global const float *F_1, __global const float *F_2, __global const float *F_3, __global const float *X_1, __global const float *X_2, __global const float *X_3, const unsigned N, const float dx, const float dtheta, const unsigned shift0, const unsigned shift1, const unsigned shift2, __global float *f_1, __global float *f_2, __global float *f_3)
    {
      unsigned i = 4*get_global_id(0)+shift0;
      unsigned j = 4*get_global_id(1)+shift1;
      unsigned k = 4*get_global_id(2)+shift2;

      int k1 = firstn1[i+N*j+N*N*k]; 
      int k2 = firstn2[i+N*j+N*N*k]; 
      int k3 = firstn3[i+N*j+N*N*k]; 

      if (k1 == -1 && k2 == -1 && k3 == -1){
      return;
      }

      float c = dtheta/(dx*dx*dx);

      int ind_1x, ind_1y, ind_1z, ind_1w;
      int ind_2x, ind_2y, ind_2z, ind_2w;
      int ind_3x, ind_3y, ind_3z, ind_3w;

      float q1, q2, q3;

      float v1x, v1y, v1z, v1w;
      float v2x, v2y, v2z, v2w;
      float v3x, v3y, v3z, v3w;

      float ws01, ws11, ws21, ws31;
      float ws41, ws51, ws61, ws71;
      float ws81, ws91, wsa1, wsb1;
      float wsc1, wsd1, wse1, wsf1;

      float ws02, ws12, ws22, ws32;
      float ws42, ws52, ws62, ws72;
      float ws82, ws92, wsa2, wsb2;
      float wsc2, wsd2, wse2, wsf2;

      float ws03, ws13, ws23, ws33;
      float ws43, ws53, ws63, ws73;
      float ws83, ws93, wsa3, wsb3;
      float wsc3, wsd3, wse3, wsf3;

      float ws04, ws14, ws24, ws34;
      float ws44, ws54, ws64, ws74;
      float ws84, ws94, wsa4, wsb4;
      float wsc4, wsd4, wse4, wsf4;

      float f_01, f_11, f_21, f_31;
      float f_41, f_51, f_61, f_71;
      float f_81, f_91, f_a1, f_b1;
      float f_c1, f_d1, f_e1, f_f1;

      float f_02, f_12, f_22, f_32;
      float f_42, f_52, f_62, f_72;
      float f_82, f_92, f_a2, f_b2;
      float f_c2, f_d2, f_e2, f_f2;

      float f_03, f_13, f_23, f_33;
      float f_43, f_53, f_63, f_73;
      float f_83, f_93, f_a3, f_b3;
      float f_c3, f_d3, f_e3, f_f3;

      float f_04, f_14, f_24, f_34;
      float f_44, f_54, f_64, f_74;
      float f_84, f_94, f_a4, f_b4;
      float f_c4, f_d4, f_e4, f_f4;

      if (k1 !=-1){
      ind_1x = (i-1 & N-1);
      ind_1y = (i & N-1);
      ind_1z = (i+1 & N-1);
      ind_1w = (i+2 & N-1);

      ind_2x = (j-1 & N-1);
      ind_2y = (j & N-1);
      ind_2z = (j+1 & N-1);
      ind_2w = (j+2 & N-1);

      ind_3x = (k-1 & N-1);
      ind_3y = (k & N-1);
      ind_3z = (k+1 & N-1);
      ind_3w = (k+2 & N-1);

      f_01=f_1[ind_1x+N*ind_2x+N*N*ind_3x];
      f_11=f_1[ind_1y+N*ind_2x+N*N*ind_3x];
      f_21=f_1[ind_1z+N*ind_2x+N*N*ind_3x];
      f_31=f_1[ind_1w+N*ind_2x+N*N*ind_3x];
      f_41=f_1[ind_1x+N*ind_2y+N*N*ind_3x];
      f_51=f_1[ind_1y+N*ind_2y+N*N*ind_3x];
      f_61=f_1[ind_1z+N*ind_2y+N*N*ind_3x];
      f_71=f_1[ind_1w+N*ind_2y+N*N*ind_3x];
      f_81=f_1[ind_1x+N*ind_2z+N*N*ind_3x];
      f_91=f_1[ind_1y+N*ind_2z+N*N*ind_3x];
      f_a1=f_1[ind_1z+N*ind_2z+N*N*ind_3x];
      f_b1=f_1[ind_1w+N*ind_2z+N*N*ind_3x];
      f_c1=f_1[ind_1x+N*ind_2w+N*N*ind_3x];
      f_d1=f_1[ind_1y+N*ind_2w+N*N*ind_3x];
      f_e1=f_1[ind_1z+N*ind_2w+N*N*ind_3x];
      f_f1=f_1[ind_1w+N*ind_2w+N*N*ind_3x];

      f_02=f_1[ind_1x+N*ind_2x+N*N*ind_3y];
      f_12=f_1[ind_1y+N*ind_2x+N*N*ind_3y];
      f_22=f_1[ind_1z+N*ind_2x+N*N*ind_3y];
      f_32=f_1[ind_1w+N*ind_2x+N*N*ind_3y];
      f_42=f_1[ind_1x+N*ind_2y+N*N*ind_3y];
      f_52=f_1[ind_1y+N*ind_2y+N*N*ind_3y];
      f_62=f_1[ind_1z+N*ind_2y+N*N*ind_3y];
      f_72=f_1[ind_1w+N*ind_2y+N*N*ind_3y];
      f_82=f_1[ind_1x+N*ind_2z+N*N*ind_3y];
      f_92=f_1[ind_1y+N*ind_2z+N*N*ind_3y];
      f_a2=f_1[ind_1z+N*ind_2z+N*N*ind_3y];
      f_b2=f_1[ind_1w+N*ind_2z+N*N*ind_3y];
      f_c2=f_1[ind_1x+N*ind_2w+N*N*ind_3y];
      f_d2=f_1[ind_1y+N*ind_2w+N*N*ind_3y];
      f_e2=f_1[ind_1z+N*ind_2w+N*N*ind_3y];
      f_f2=f_1[ind_1w+N*ind_2w+N*N*ind_3y];

      f_03=f_1[ind_1x+N*ind_2x+N*N*ind_3z];
      f_13=f_1[ind_1y+N*ind_2x+N*N*ind_3z];
      f_23=f_1[ind_1z+N*ind_2x+N*N*ind_3z];
      f_33=f_1[ind_1w+N*ind_2x+N*N*ind_3z];
      f_43=f_1[ind_1x+N*ind_2y+N*N*ind_3z];
      f_53=f_1[ind_1y+N*ind_2y+N*N*ind_3z];
      f_63=f_1[ind_1z+N*ind_2y+N*N*ind_3z];
      f_73=f_1[ind_1w+N*ind_2y+N*N*ind_3z];
      f_83=f_1[ind_1x+N*ind_2z+N*N*ind_3z];
      f_93=f_1[ind_1y+N*ind_2z+N*N*ind_3z];
      f_a3=f_1[ind_1z+N*ind_2z+N*N*ind_3z];
      f_b3=f_1[ind_1w+N*ind_2z+N*N*ind_3z];
      f_c3=f_1[ind_1x+N*ind_2w+N*N*ind_3z];
      f_d3=f_1[ind_1y+N*ind_2w+N*N*ind_3z];
      f_e3=f_1[ind_1z+N*ind_2w+N*N*ind_3z];
      f_f3=f_1[ind_1w+N*ind_2w+N*N*ind_3z];

      f_04=f_1[ind_1x+N*ind_2x+N*N*ind_3w];
      f_14=f_1[ind_1y+N*ind_2x+N*N*ind_3w];
      f_24=f_1[ind_1z+N*ind_2x+N*N*ind_3w];
      f_34=f_1[ind_1w+N*ind_2x+N*N*ind_3w];
      f_44=f_1[ind_1x+N*ind_2y+N*N*ind_3w];
      f_54=f_1[ind_1y+N*ind_2y+N*N*ind_3w];
      f_64=f_1[ind_1z+N*ind_2y+N*N*ind_3w];
      f_74=f_1[ind_1w+N*ind_2y+N*N*ind_3w];
      f_84=f_1[ind_1x+N*ind_2z+N*N*ind_3w];
      f_94=f_1[ind_1y+N*ind_2z+N*N*ind_3w];
      f_a4=f_1[ind_1z+N*ind_2z+N*N*ind_3w];
      f_b4=f_1[ind_1w+N*ind_2z+N*N*ind_3w];
      f_c4=f_1[ind_1x+N*ind_2w+N*N*ind_3w];
      f_d4=f_1[ind_1y+N*ind_2w+N*N*ind_3w];
      f_e4=f_1[ind_1z+N*ind_2w+N*N*ind_3w];
      f_f4=f_1[ind_1w+N*ind_2w+N*N*ind_3w];
      }
 
      while(k1 != -1)
      {
      float s_1_stag = (X_1[k1]+0.5)/dx;
      float s_2_stag = (X_2[k1]+0.5)/dx;       
      float s_3_stag = (X_3[k1]+0.5)/dx;       
      int i_1_stag = convert_int(floor(s_1_stag));
      int i_2_stag = convert_int(floor(s_2_stag));
      int i_3_stag = convert_int(floor(s_3_stag));
      float r_1_stag = s_1_stag-i_1_stag;
      float r_2_stag = s_2_stag-i_2_stag;
      float r_3_stag = s_3_stag-i_3_stag;
      float s_1_c = (X_1[k1]+0.5-dx/2)/dx;
      float s_2_c = (X_2[k1]+0.5-dx/2)/dx;        
      float s_3_c = (X_3[k1]+0.5-dx/2)/dx;        
      int i_1_c = convert_int(floor(s_1_c));
      int i_2_c = convert_int(floor(s_2_c));
      int i_3_c = convert_int(floor(s_3_c));
      float r_1_c = s_1_c-i_1_c;
      float r_2_c = s_2_c-i_2_c;
      float r_3_c = s_3_c-i_3_c;

      q1 = sqrt(1.+4.0*r_1_stag*(1-r_1_stag)); 
      q2 = sqrt(1.+4.0*r_2_c*(1-r_2_c));
      q3 = sqrt(1.+4.0*r_3_c*(1-r_3_c));

      v1x = 3.-2.*r_1_stag-q1; 
      v1y = 3.-2.*r_1_stag+q1; 
      v1z = 1.+2.*r_1_stag+q1; 
      v1w = 1.+2.*r_1_stag-q1; 
      v1x = v1x/8.;
      v1y = v1y/8.;
      v1z = v1z/8.;
      v1w = v1w/8.;

      v2x = 3.-2.*r_2_c-q2; 
      v2y = 3.-2.*r_2_c+q2; 
      v2z = 1.+2.*r_2_c+q2; 
      v2w = 1.+2.*r_2_c-q2; 
      v2x = v2x/8.;
      v2y = v2y/8.;
      v2z = v2z/8.;
      v2w = v2w/8.;

      v3x = 3.-2.*r_3_c-q3; 
      v3y = 3.-2.*r_3_c+q3; 
      v3z = 1.+2.*r_3_c+q3; 
      v3w = 1.+2.*r_3_c-q3; 
      v3x = v3x/8.;
      v3y = v3y/8.;
      v3z = v3z/8.;
      v3w = v3w/8.;
      
      ws01 = v1x*v2x*v3x;
      ws11 = v1y*v2x*v3x;
      ws21 = v1z*v2x*v3x;
      ws31 = v1w*v2x*v3x;
      ws41 = v1x*v2y*v3x;
      ws51 = v1y*v2y*v3x;
      ws61 = v1z*v2y*v3x;
      ws71 = v1w*v2y*v3x;
      ws81 = v1x*v2z*v3x;
      ws91 = v1y*v2z*v3x;
      wsa1 = v1z*v2z*v3x;
      wsb1 = v1w*v2z*v3x;
      wsc1 = v1x*v2w*v3x;
      wsd1 = v1y*v2w*v3x;
      wse1 = v1z*v2w*v3x;
      wsf1 = v1w*v2w*v3x;
      
      ws02 = v1x*v2x*v3y;
      ws12 = v1y*v2x*v3y;
      ws22 = v1z*v2x*v3y;
      ws32 = v1w*v2x*v3y;
      ws42 = v1x*v2y*v3y;
      ws52 = v1y*v2y*v3y;
      ws62 = v1z*v2y*v3y;
      ws72 = v1w*v2y*v3y;
      ws82 = v1x*v2z*v3y;
      ws92 = v1y*v2z*v3y;
      wsa2 = v1z*v2z*v3y;
      wsb2 = v1w*v2z*v3y;
      wsc2 = v1x*v2w*v3y;
      wsd2 = v1y*v2w*v3y;
      wse2 = v1z*v2w*v3y;
      wsf2 = v1w*v2w*v3y;

      ws03 = v1x*v2x*v3z;
      ws13 = v1y*v2x*v3z;
      ws23 = v1z*v2x*v3z;
      ws33 = v1w*v2x*v3z;
      ws43 = v1x*v2y*v3z;
      ws53 = v1y*v2y*v3z;
      ws63 = v1z*v2y*v3z;
      ws73 = v1w*v2y*v3z;
      ws83 = v1x*v2z*v3z;
      ws93 = v1y*v2z*v3z;
      wsa3 = v1z*v2z*v3z;
      wsb3 = v1w*v2z*v3z;
      wsc3 = v1x*v2w*v3z;
      wsd3 = v1y*v2w*v3z;
      wse3 = v1z*v2w*v3z;
      wsf3 = v1w*v2w*v3z;

      ws04 = v1x*v2x*v3w;
      ws14 = v1y*v2x*v3w;
      ws24 = v1z*v2x*v3w;
      ws34 = v1w*v2x*v3w;
      ws44 = v1x*v2y*v3w;
      ws54 = v1y*v2y*v3w;
      ws64 = v1z*v2y*v3w;
      ws74 = v1w*v2y*v3w;
      ws84 = v1x*v2z*v3w;
      ws94 = v1y*v2z*v3w;
      wsa4 = v1z*v2z*v3w;
      wsb4 = v1w*v2z*v3w;
      wsc4 = v1x*v2w*v3w;
      wsd4 = v1y*v2w*v3w;
      wse4 = v1z*v2w*v3w;
      wsf4 = v1w*v2w*v3w;

      float my_F_1 = F_1[k1];
      f_01 += c*my_F_1*ws01;
      f_11 += c*my_F_1*ws11;
      f_21 += c*my_F_1*ws21;
      f_31 += c*my_F_1*ws31;
      f_41 += c*my_F_1*ws41;
      f_51 += c*my_F_1*ws51;
      f_61 += c*my_F_1*ws61;
      f_71 += c*my_F_1*ws71;
      f_81 += c*my_F_1*ws81;
      f_91 += c*my_F_1*ws91;
      f_a1 += c*my_F_1*wsa1;
      f_b1 += c*my_F_1*wsb1;
      f_c1 += c*my_F_1*wsc1;
      f_d1 += c*my_F_1*wsd1;
      f_e1 += c*my_F_1*wse1;
      f_f1 += c*my_F_1*wsf1;

      f_02 += c*my_F_1*ws02;
      f_12 += c*my_F_1*ws12;
      f_22 += c*my_F_1*ws22;
      f_32 += c*my_F_1*ws32;
      f_42 += c*my_F_1*ws42;
      f_52 += c*my_F_1*ws52;
      f_62 += c*my_F_1*ws62;
      f_72 += c*my_F_1*ws72;
      f_82 += c*my_F_1*ws82;
      f_92 += c*my_F_1*ws92;
      f_a2 += c*my_F_1*wsa2;
      f_b2 += c*my_F_1*wsb2;
      f_c2 += c*my_F_1*wsc2;
      f_d2 += c*my_F_1*wsd2;
      f_e2 += c*my_F_1*wse2;
      f_f2 += c*my_F_1*wsf2;

      f_03 += c*my_F_1*ws03;
      f_13 += c*my_F_1*ws13;
      f_23 += c*my_F_1*ws23;
      f_33 += c*my_F_1*ws33;
      f_43 += c*my_F_1*ws43;
      f_53 += c*my_F_1*ws53;
      f_63 += c*my_F_1*ws63;
      f_73 += c*my_F_1*ws73;
      f_83 += c*my_F_1*ws83;
      f_93 += c*my_F_1*ws93;
      f_a3 += c*my_F_1*wsa3;
      f_b3 += c*my_F_1*wsb3;
      f_c3 += c*my_F_1*wsc3;
      f_d3 += c*my_F_1*wsd3;
      f_e3 += c*my_F_1*wse3;
      f_f3 += c*my_F_1*wsf3;

      f_04 += c*my_F_1*ws04;
      f_14 += c*my_F_1*ws14;
      f_24 += c*my_F_1*ws24;
      f_34 += c*my_F_1*ws34;
      f_44 += c*my_F_1*ws44;
      f_54 += c*my_F_1*ws54;
      f_64 += c*my_F_1*ws64;
      f_74 += c*my_F_1*ws74;
      f_84 += c*my_F_1*ws84;
      f_94 += c*my_F_1*ws94;
      f_a4 += c*my_F_1*wsa4;
      f_b4 += c*my_F_1*wsb4;
      f_c4 += c*my_F_1*wsc4;
      f_d4 += c*my_F_1*wsd4;
      f_e4 += c*my_F_1*wse4;
      f_f4 += c*my_F_1*wsf4;

      k1 = nextn1[k1];
      if (k1 == -1){
      f_1[ind_1x+N*ind_2x+N*N*ind_3x]=f_01;
      f_1[ind_1y+N*ind_2x+N*N*ind_3x]=f_11;
      f_1[ind_1z+N*ind_2x+N*N*ind_3x]=f_21;
      f_1[ind_1w+N*ind_2x+N*N*ind_3x]=f_31;
      f_1[ind_1x+N*ind_2y+N*N*ind_3x]=f_41;
      f_1[ind_1y+N*ind_2y+N*N*ind_3x]=f_51;
      f_1[ind_1z+N*ind_2y+N*N*ind_3x]=f_61;
      f_1[ind_1w+N*ind_2y+N*N*ind_3x]=f_71;
      f_1[ind_1x+N*ind_2z+N*N*ind_3x]=f_81;
      f_1[ind_1y+N*ind_2z+N*N*ind_3x]=f_91;
      f_1[ind_1z+N*ind_2z+N*N*ind_3x]=f_a1;
      f_1[ind_1w+N*ind_2z+N*N*ind_3x]=f_b1;
      f_1[ind_1x+N*ind_2w+N*N*ind_3x]=f_c1;
      f_1[ind_1y+N*ind_2w+N*N*ind_3x]=f_d1;
      f_1[ind_1z+N*ind_2w+N*N*ind_3x]=f_e1;
      f_1[ind_1w+N*ind_2w+N*N*ind_3x]=f_f1;

      f_1[ind_1x+N*ind_2x+N*N*ind_3y]=f_02;
      f_1[ind_1y+N*ind_2x+N*N*ind_3y]=f_12;
      f_1[ind_1z+N*ind_2x+N*N*ind_3y]=f_22;
      f_1[ind_1w+N*ind_2x+N*N*ind_3y]=f_32;
      f_1[ind_1x+N*ind_2y+N*N*ind_3y]=f_42;
      f_1[ind_1y+N*ind_2y+N*N*ind_3y]=f_52;
      f_1[ind_1z+N*ind_2y+N*N*ind_3y]=f_62;
      f_1[ind_1w+N*ind_2y+N*N*ind_3y]=f_72;
      f_1[ind_1x+N*ind_2z+N*N*ind_3y]=f_82;
      f_1[ind_1y+N*ind_2z+N*N*ind_3y]=f_92;
      f_1[ind_1z+N*ind_2z+N*N*ind_3y]=f_a2;
      f_1[ind_1w+N*ind_2z+N*N*ind_3y]=f_b2;
      f_1[ind_1x+N*ind_2w+N*N*ind_3y]=f_c2;
      f_1[ind_1y+N*ind_2w+N*N*ind_3y]=f_d2;
      f_1[ind_1z+N*ind_2w+N*N*ind_3y]=f_e2;
      f_1[ind_1w+N*ind_2w+N*N*ind_3y]=f_f2;

      f_1[ind_1x+N*ind_2x+N*N*ind_3z]=f_03;
      f_1[ind_1y+N*ind_2x+N*N*ind_3z]=f_13;
      f_1[ind_1z+N*ind_2x+N*N*ind_3z]=f_23;
      f_1[ind_1w+N*ind_2x+N*N*ind_3z]=f_33;
      f_1[ind_1x+N*ind_2y+N*N*ind_3z]=f_43;
      f_1[ind_1y+N*ind_2y+N*N*ind_3z]=f_53;
      f_1[ind_1z+N*ind_2y+N*N*ind_3z]=f_63;
      f_1[ind_1w+N*ind_2y+N*N*ind_3z]=f_73;
      f_1[ind_1x+N*ind_2z+N*N*ind_3z]=f_83;
      f_1[ind_1y+N*ind_2z+N*N*ind_3z]=f_93;
      f_1[ind_1z+N*ind_2z+N*N*ind_3z]=f_a3;
      f_1[ind_1w+N*ind_2z+N*N*ind_3z]=f_b3;
      f_1[ind_1x+N*ind_2w+N*N*ind_3z]=f_c3;
      f_1[ind_1y+N*ind_2w+N*N*ind_3z]=f_d3;
      f_1[ind_1z+N*ind_2w+N*N*ind_3z]=f_e3;
      f_1[ind_1w+N*ind_2w+N*N*ind_3z]=f_f3;

      f_1[ind_1x+N*ind_2x+N*N*ind_3w]=f_04;
      f_1[ind_1y+N*ind_2x+N*N*ind_3w]=f_14;
      f_1[ind_1z+N*ind_2x+N*N*ind_3w]=f_24;
      f_1[ind_1w+N*ind_2x+N*N*ind_3w]=f_34;
      f_1[ind_1x+N*ind_2y+N*N*ind_3w]=f_44;
      f_1[ind_1y+N*ind_2y+N*N*ind_3w]=f_54;
      f_1[ind_1z+N*ind_2y+N*N*ind_3w]=f_64;
      f_1[ind_1w+N*ind_2y+N*N*ind_3w]=f_74;
      f_1[ind_1x+N*ind_2z+N*N*ind_3w]=f_84;
      f_1[ind_1y+N*ind_2z+N*N*ind_3w]=f_94;
      f_1[ind_1z+N*ind_2z+N*N*ind_3w]=f_a4;
      f_1[ind_1w+N*ind_2z+N*N*ind_3w]=f_b4;
      f_1[ind_1x+N*ind_2w+N*N*ind_3w]=f_c4;
      f_1[ind_1y+N*ind_2w+N*N*ind_3w]=f_d4;
      f_1[ind_1z+N*ind_2w+N*N*ind_3w]=f_e4;
      f_1[ind_1w+N*ind_2w+N*N*ind_3w]=f_f4;
      }
      }

      if (k2 !=-1){
      ind_1x = (i-1 & N-1);
      ind_1y = (i & N-1);
      ind_1z = (i+1 & N-1);
      ind_1w = (i+2 & N-1);

      ind_2x = (j-1 & N-1);
      ind_2y = (j & N-1);
      ind_2z = (j+1 & N-1);
      ind_2w = (j+2 & N-1);

      ind_3x = (k-1 & N-1);
      ind_3y = (k & N-1);
      ind_3z = (k+1 & N-1);
      ind_3w = (k+2 & N-1);

      f_01=f_2[ind_1x+N*ind_2x+N*N*ind_3x];
      f_11=f_2[ind_1y+N*ind_2x+N*N*ind_3x];
      f_21=f_2[ind_1z+N*ind_2x+N*N*ind_3x];
      f_31=f_2[ind_1w+N*ind_2x+N*N*ind_3x];
      f_41=f_2[ind_1x+N*ind_2y+N*N*ind_3x];
      f_51=f_2[ind_1y+N*ind_2y+N*N*ind_3x];
      f_61=f_2[ind_1z+N*ind_2y+N*N*ind_3x];
      f_71=f_2[ind_1w+N*ind_2y+N*N*ind_3x];
      f_81=f_2[ind_1x+N*ind_2z+N*N*ind_3x];
      f_91=f_2[ind_1y+N*ind_2z+N*N*ind_3x];
      f_a1=f_2[ind_1z+N*ind_2z+N*N*ind_3x];
      f_b1=f_2[ind_1w+N*ind_2z+N*N*ind_3x];
      f_c1=f_2[ind_1x+N*ind_2w+N*N*ind_3x];
      f_d1=f_2[ind_1y+N*ind_2w+N*N*ind_3x];
      f_e1=f_2[ind_1z+N*ind_2w+N*N*ind_3x];
      f_f1=f_2[ind_1w+N*ind_2w+N*N*ind_3x];

      f_02=f_2[ind_1x+N*ind_2x+N*N*ind_3y];
      f_12=f_2[ind_1y+N*ind_2x+N*N*ind_3y];
      f_22=f_2[ind_1z+N*ind_2x+N*N*ind_3y];
      f_32=f_2[ind_1w+N*ind_2x+N*N*ind_3y];
      f_42=f_2[ind_1x+N*ind_2y+N*N*ind_3y];
      f_52=f_2[ind_1y+N*ind_2y+N*N*ind_3y];
      f_62=f_2[ind_1z+N*ind_2y+N*N*ind_3y];
      f_72=f_2[ind_1w+N*ind_2y+N*N*ind_3y];
      f_82=f_2[ind_1x+N*ind_2z+N*N*ind_3y];
      f_92=f_2[ind_1y+N*ind_2z+N*N*ind_3y];
      f_a2=f_2[ind_1z+N*ind_2z+N*N*ind_3y];
      f_b2=f_2[ind_1w+N*ind_2z+N*N*ind_3y];
      f_c2=f_2[ind_1x+N*ind_2w+N*N*ind_3y];
      f_d2=f_2[ind_1y+N*ind_2w+N*N*ind_3y];
      f_e2=f_2[ind_1z+N*ind_2w+N*N*ind_3y];
      f_f2=f_2[ind_1w+N*ind_2w+N*N*ind_3y];

      f_03=f_2[ind_1x+N*ind_2x+N*N*ind_3z];
      f_13=f_2[ind_1y+N*ind_2x+N*N*ind_3z];
      f_23=f_2[ind_1z+N*ind_2x+N*N*ind_3z];
      f_33=f_2[ind_1w+N*ind_2x+N*N*ind_3z];
      f_43=f_2[ind_1x+N*ind_2y+N*N*ind_3z];
      f_53=f_2[ind_1y+N*ind_2y+N*N*ind_3z];
      f_63=f_2[ind_1z+N*ind_2y+N*N*ind_3z];
      f_73=f_2[ind_1w+N*ind_2y+N*N*ind_3z];
      f_83=f_2[ind_1x+N*ind_2z+N*N*ind_3z];
      f_93=f_2[ind_1y+N*ind_2z+N*N*ind_3z];
      f_a3=f_2[ind_1z+N*ind_2z+N*N*ind_3z];
      f_b3=f_2[ind_1w+N*ind_2z+N*N*ind_3z];
      f_c3=f_2[ind_1x+N*ind_2w+N*N*ind_3z];
      f_d3=f_2[ind_1y+N*ind_2w+N*N*ind_3z];
      f_e3=f_2[ind_1z+N*ind_2w+N*N*ind_3z];
      f_f3=f_2[ind_1w+N*ind_2w+N*N*ind_3z];

      f_04=f_2[ind_1x+N*ind_2x+N*N*ind_3w];
      f_14=f_2[ind_1y+N*ind_2x+N*N*ind_3w];
      f_24=f_2[ind_1z+N*ind_2x+N*N*ind_3w];
      f_34=f_2[ind_1w+N*ind_2x+N*N*ind_3w];
      f_44=f_2[ind_1x+N*ind_2y+N*N*ind_3w];
      f_54=f_2[ind_1y+N*ind_2y+N*N*ind_3w];
      f_64=f_2[ind_1z+N*ind_2y+N*N*ind_3w];
      f_74=f_2[ind_1w+N*ind_2y+N*N*ind_3w];
      f_84=f_2[ind_1x+N*ind_2z+N*N*ind_3w];
      f_94=f_2[ind_1y+N*ind_2z+N*N*ind_3w];
      f_a4=f_2[ind_1z+N*ind_2z+N*N*ind_3w];
      f_b4=f_2[ind_1w+N*ind_2z+N*N*ind_3w];
      f_c4=f_2[ind_1x+N*ind_2w+N*N*ind_3w];
      f_d4=f_2[ind_1y+N*ind_2w+N*N*ind_3w];
      f_e4=f_2[ind_1z+N*ind_2w+N*N*ind_3w];
      f_f4=f_2[ind_1w+N*ind_2w+N*N*ind_3w];
      }
 
      while(k2 != -1)
      {
      float s_1_stag = (X_1[k2]+0.5)/dx;
      float s_2_stag = (X_2[k2]+0.5)/dx;       
      float s_3_stag = (X_3[k2]+0.5)/dx;       
      int i_1_stag = convert_int(floor(s_1_stag));
      int i_2_stag = convert_int(floor(s_2_stag));
      int i_3_stag = convert_int(floor(s_3_stag));
      float r_1_stag = s_1_stag-i_1_stag;
      float r_2_stag = s_2_stag-i_2_stag;
      float r_3_stag = s_3_stag-i_3_stag;
      float s_1_c = (X_1[k2]+0.5-dx/2)/dx;
      float s_2_c = (X_2[k2]+0.5-dx/2)/dx;        
      float s_3_c = (X_3[k2]+0.5-dx/2)/dx;        
      int i_1_c = convert_int(floor(s_1_c));
      int i_2_c = convert_int(floor(s_2_c));
      int i_3_c = convert_int(floor(s_3_c));
      float r_1_c = s_1_c-i_1_c;
      float r_2_c = s_2_c-i_2_c;
      float r_3_c = s_3_c-i_3_c;
      
      q1 = sqrt(1.+4.0*r_1_c*(1-r_1_c)); 
      q2 = sqrt(1.+4.0*r_2_stag*(1-r_2_stag));
      q3 = sqrt(1.+4.0*r_3_c*(1-r_3_c));

      v1x = 3.-2.*r_1_c-q1; 
      v1y = 3.-2.*r_1_c+q1; 
      v1z = 1.+2.*r_1_c+q1; 
      v1w = 1.+2.*r_1_c-q1; 
      v1x = v1x/8.;
      v1y = v1y/8.;
      v1z = v1z/8.;
      v1w = v1w/8.;

      v2x = 3.-2.*r_2_stag-q2; 
      v2y = 3.-2.*r_2_stag+q2; 
      v2z = 1.+2.*r_2_stag+q2; 
      v2w = 1.+2.*r_2_stag-q2; 
      v2x = v2x/8.;
      v2y = v2y/8.;
      v2z = v2z/8.;
      v2w = v2w/8.;

      v3x = 3.-2.*r_3_c-q3; 
      v3y = 3.-2.*r_3_c+q3; 
      v3z = 1.+2.*r_3_c+q3; 
      v3w = 1.+2.*r_3_c-q3; 
      v3x = v3x/8.;
      v3y = v3y/8.;
      v3z = v3z/8.;
      v3w = v3w/8.;
      
      ws01 = v1x*v2x*v3x;
      ws11 = v1y*v2x*v3x;
      ws21 = v1z*v2x*v3x;
      ws31 = v1w*v2x*v3x;
      ws41 = v1x*v2y*v3x;
      ws51 = v1y*v2y*v3x;
      ws61 = v1z*v2y*v3x;
      ws71 = v1w*v2y*v3x;
      ws81 = v1x*v2z*v3x;
      ws91 = v1y*v2z*v3x;
      wsa1 = v1z*v2z*v3x;
      wsb1 = v1w*v2z*v3x;
      wsc1 = v1x*v2w*v3x;
      wsd1 = v1y*v2w*v3x;
      wse1 = v1z*v2w*v3x;
      wsf1 = v1w*v2w*v3x;
      
      ws02 = v1x*v2x*v3y;
      ws12 = v1y*v2x*v3y;
      ws22 = v1z*v2x*v3y;
      ws32 = v1w*v2x*v3y;
      ws42 = v1x*v2y*v3y;
      ws52 = v1y*v2y*v3y;
      ws62 = v1z*v2y*v3y;
      ws72 = v1w*v2y*v3y;
      ws82 = v1x*v2z*v3y;
      ws92 = v1y*v2z*v3y;
      wsa2 = v1z*v2z*v3y;
      wsb2 = v1w*v2z*v3y;
      wsc2 = v1x*v2w*v3y;
      wsd2 = v1y*v2w*v3y;
      wse2 = v1z*v2w*v3y;
      wsf2 = v1w*v2w*v3y;

      ws03 = v1x*v2x*v3z;
      ws13 = v1y*v2x*v3z;
      ws23 = v1z*v2x*v3z;
      ws33 = v1w*v2x*v3z;
      ws43 = v1x*v2y*v3z;
      ws53 = v1y*v2y*v3z;
      ws63 = v1z*v2y*v3z;
      ws73 = v1w*v2y*v3z;
      ws83 = v1x*v2z*v3z;
      ws93 = v1y*v2z*v3z;
      wsa3 = v1z*v2z*v3z;
      wsb3 = v1w*v2z*v3z;
      wsc3 = v1x*v2w*v3z;
      wsd3 = v1y*v2w*v3z;
      wse3 = v1z*v2w*v3z;
      wsf3 = v1w*v2w*v3z;

      ws04 = v1x*v2x*v3w;
      ws14 = v1y*v2x*v3w;
      ws24 = v1z*v2x*v3w;
      ws34 = v1w*v2x*v3w;
      ws44 = v1x*v2y*v3w;
      ws54 = v1y*v2y*v3w;
      ws64 = v1z*v2y*v3w;
      ws74 = v1w*v2y*v3w;
      ws84 = v1x*v2z*v3w;
      ws94 = v1y*v2z*v3w;
      wsa4 = v1z*v2z*v3w;
      wsb4 = v1w*v2z*v3w;
      wsc4 = v1x*v2w*v3w;
      wsd4 = v1y*v2w*v3w;
      wse4 = v1z*v2w*v3w;
      wsf4 = v1w*v2w*v3w;

      float my_F_2 = F_2[k2];
      f_01 += c*my_F_2*ws01;
      f_11 += c*my_F_2*ws11;
      f_21 += c*my_F_2*ws21;
      f_31 += c*my_F_2*ws31;
      f_41 += c*my_F_2*ws41;
      f_51 += c*my_F_2*ws51;
      f_61 += c*my_F_2*ws61;
      f_71 += c*my_F_2*ws71;
      f_81 += c*my_F_2*ws81;
      f_91 += c*my_F_2*ws91;
      f_a1 += c*my_F_2*wsa1;
      f_b1 += c*my_F_2*wsb1;
      f_c1 += c*my_F_2*wsc1;
      f_d1 += c*my_F_2*wsd1;
      f_e1 += c*my_F_2*wse1;
      f_f1 += c*my_F_2*wsf1;

      f_02 += c*my_F_2*ws02;
      f_12 += c*my_F_2*ws12;
      f_22 += c*my_F_2*ws22;
      f_32 += c*my_F_2*ws32;
      f_42 += c*my_F_2*ws42;
      f_52 += c*my_F_2*ws52;
      f_62 += c*my_F_2*ws62;
      f_72 += c*my_F_2*ws72;
      f_82 += c*my_F_2*ws82;
      f_92 += c*my_F_2*ws92;
      f_a2 += c*my_F_2*wsa2;
      f_b2 += c*my_F_2*wsb2;
      f_c2 += c*my_F_2*wsc2;
      f_d2 += c*my_F_2*wsd2;
      f_e2 += c*my_F_2*wse2;
      f_f2 += c*my_F_2*wsf2;

      f_03 += c*my_F_2*ws03;
      f_13 += c*my_F_2*ws13;
      f_23 += c*my_F_2*ws23;
      f_33 += c*my_F_2*ws33;
      f_43 += c*my_F_2*ws43;
      f_53 += c*my_F_2*ws53;
      f_63 += c*my_F_2*ws63;
      f_73 += c*my_F_2*ws73;
      f_83 += c*my_F_2*ws83;
      f_93 += c*my_F_2*ws93;
      f_a3 += c*my_F_2*wsa3;
      f_b3 += c*my_F_2*wsb3;
      f_c3 += c*my_F_2*wsc3;
      f_d3 += c*my_F_2*wsd3;
      f_e3 += c*my_F_2*wse3;
      f_f3 += c*my_F_2*wsf3;

      f_04 += c*my_F_2*ws04;
      f_14 += c*my_F_2*ws14;
      f_24 += c*my_F_2*ws24;
      f_34 += c*my_F_2*ws34;
      f_44 += c*my_F_2*ws44;
      f_54 += c*my_F_2*ws54;
      f_64 += c*my_F_2*ws64;
      f_74 += c*my_F_2*ws74;
      f_84 += c*my_F_2*ws84;
      f_94 += c*my_F_2*ws94;
      f_a4 += c*my_F_2*wsa4;
      f_b4 += c*my_F_2*wsb4;
      f_c4 += c*my_F_2*wsc4;
      f_d4 += c*my_F_2*wsd4;
      f_e4 += c*my_F_2*wse4;
      f_f4 += c*my_F_2*wsf4;

      k2 = nextn2[k2];
      if (k2 == -1){
      f_2[ind_1x+N*ind_2x+N*N*ind_3x]=f_01;
      f_2[ind_1y+N*ind_2x+N*N*ind_3x]=f_11;
      f_2[ind_1z+N*ind_2x+N*N*ind_3x]=f_21;
      f_2[ind_1w+N*ind_2x+N*N*ind_3x]=f_31;
      f_2[ind_1x+N*ind_2y+N*N*ind_3x]=f_41;
      f_2[ind_1y+N*ind_2y+N*N*ind_3x]=f_51;
      f_2[ind_1z+N*ind_2y+N*N*ind_3x]=f_61;
      f_2[ind_1w+N*ind_2y+N*N*ind_3x]=f_71;
      f_2[ind_1x+N*ind_2z+N*N*ind_3x]=f_81;
      f_2[ind_1y+N*ind_2z+N*N*ind_3x]=f_91;
      f_2[ind_1z+N*ind_2z+N*N*ind_3x]=f_a1;
      f_2[ind_1w+N*ind_2z+N*N*ind_3x]=f_b1;
      f_2[ind_1x+N*ind_2w+N*N*ind_3x]=f_c1;
      f_2[ind_1y+N*ind_2w+N*N*ind_3x]=f_d1;
      f_2[ind_1z+N*ind_2w+N*N*ind_3x]=f_e1;
      f_2[ind_1w+N*ind_2w+N*N*ind_3x]=f_f1;

      f_2[ind_1x+N*ind_2x+N*N*ind_3y]=f_02;
      f_2[ind_1y+N*ind_2x+N*N*ind_3y]=f_12;
      f_2[ind_1z+N*ind_2x+N*N*ind_3y]=f_22;
      f_2[ind_1w+N*ind_2x+N*N*ind_3y]=f_32;
      f_2[ind_1x+N*ind_2y+N*N*ind_3y]=f_42;
      f_2[ind_1y+N*ind_2y+N*N*ind_3y]=f_52;
      f_2[ind_1z+N*ind_2y+N*N*ind_3y]=f_62;
      f_2[ind_1w+N*ind_2y+N*N*ind_3y]=f_72;
      f_2[ind_1x+N*ind_2z+N*N*ind_3y]=f_82;
      f_2[ind_1y+N*ind_2z+N*N*ind_3y]=f_92;
      f_2[ind_1z+N*ind_2z+N*N*ind_3y]=f_a2;
      f_2[ind_1w+N*ind_2z+N*N*ind_3y]=f_b2;
      f_2[ind_1x+N*ind_2w+N*N*ind_3y]=f_c2;
      f_2[ind_1y+N*ind_2w+N*N*ind_3y]=f_d2;
      f_2[ind_1z+N*ind_2w+N*N*ind_3y]=f_e2;
      f_2[ind_1w+N*ind_2w+N*N*ind_3y]=f_f2;

      f_2[ind_1x+N*ind_2x+N*N*ind_3z]=f_03;
      f_2[ind_1y+N*ind_2x+N*N*ind_3z]=f_13;
      f_2[ind_1z+N*ind_2x+N*N*ind_3z]=f_23;
      f_2[ind_1w+N*ind_2x+N*N*ind_3z]=f_33;
      f_2[ind_1x+N*ind_2y+N*N*ind_3z]=f_43;
      f_2[ind_1y+N*ind_2y+N*N*ind_3z]=f_53;
      f_2[ind_1z+N*ind_2y+N*N*ind_3z]=f_63;
      f_2[ind_1w+N*ind_2y+N*N*ind_3z]=f_73;
      f_2[ind_1x+N*ind_2z+N*N*ind_3z]=f_83;
      f_2[ind_1y+N*ind_2z+N*N*ind_3z]=f_93;
      f_2[ind_1z+N*ind_2z+N*N*ind_3z]=f_a3;
      f_2[ind_1w+N*ind_2z+N*N*ind_3z]=f_b3;
      f_2[ind_1x+N*ind_2w+N*N*ind_3z]=f_c3;
      f_2[ind_1y+N*ind_2w+N*N*ind_3z]=f_d3;
      f_2[ind_1z+N*ind_2w+N*N*ind_3z]=f_e3;
      f_2[ind_1w+N*ind_2w+N*N*ind_3z]=f_f3;

      f_2[ind_1x+N*ind_2x+N*N*ind_3w]=f_04;
      f_2[ind_1y+N*ind_2x+N*N*ind_3w]=f_14;
      f_2[ind_1z+N*ind_2x+N*N*ind_3w]=f_24;
      f_2[ind_1w+N*ind_2x+N*N*ind_3w]=f_34;
      f_2[ind_1x+N*ind_2y+N*N*ind_3w]=f_44;
      f_2[ind_1y+N*ind_2y+N*N*ind_3w]=f_54;
      f_2[ind_1z+N*ind_2y+N*N*ind_3w]=f_64;
      f_2[ind_1w+N*ind_2y+N*N*ind_3w]=f_74;
      f_2[ind_1x+N*ind_2z+N*N*ind_3w]=f_84;
      f_2[ind_1y+N*ind_2z+N*N*ind_3w]=f_94;
      f_2[ind_1z+N*ind_2z+N*N*ind_3w]=f_a4;
      f_2[ind_1w+N*ind_2z+N*N*ind_3w]=f_b4;
      f_2[ind_1x+N*ind_2w+N*N*ind_3w]=f_c4;
      f_2[ind_1y+N*ind_2w+N*N*ind_3w]=f_d4;
      f_2[ind_1z+N*ind_2w+N*N*ind_3w]=f_e4;
      f_2[ind_1w+N*ind_2w+N*N*ind_3w]=f_f4;
      }
      }

      if (k3 !=-1){
      ind_1x = (i-1 & N-1);
      ind_1y = (i & N-1);
      ind_1z = (i+1 & N-1);
      ind_1w = (i+2 & N-1);

      ind_2x = (j-1 & N-1);
      ind_2y = (j & N-1);
      ind_2z = (j+1 & N-1);
      ind_2w = (j+2 & N-1);

      ind_3x = (k-1 & N-1);
      ind_3y = (k & N-1);
      ind_3z = (k+1 & N-1);
      ind_3w = (k+2 & N-1);

      f_01=f_3[ind_1x+N*ind_2x+N*N*ind_3x];
      f_11=f_3[ind_1y+N*ind_2x+N*N*ind_3x];
      f_21=f_3[ind_1z+N*ind_2x+N*N*ind_3x];
      f_31=f_3[ind_1w+N*ind_2x+N*N*ind_3x];
      f_41=f_3[ind_1x+N*ind_2y+N*N*ind_3x];
      f_51=f_3[ind_1y+N*ind_2y+N*N*ind_3x];
      f_61=f_3[ind_1z+N*ind_2y+N*N*ind_3x];
      f_71=f_3[ind_1w+N*ind_2y+N*N*ind_3x];
      f_81=f_3[ind_1x+N*ind_2z+N*N*ind_3x];
      f_91=f_3[ind_1y+N*ind_2z+N*N*ind_3x];
      f_a1=f_3[ind_1z+N*ind_2z+N*N*ind_3x];
      f_b1=f_3[ind_1w+N*ind_2z+N*N*ind_3x];
      f_c1=f_3[ind_1x+N*ind_2w+N*N*ind_3x];
      f_d1=f_3[ind_1y+N*ind_2w+N*N*ind_3x];
      f_e1=f_3[ind_1z+N*ind_2w+N*N*ind_3x];
      f_f1=f_3[ind_1w+N*ind_2w+N*N*ind_3x];

      f_02=f_3[ind_1x+N*ind_2x+N*N*ind_3y];
      f_12=f_3[ind_1y+N*ind_2x+N*N*ind_3y];
      f_22=f_3[ind_1z+N*ind_2x+N*N*ind_3y];
      f_32=f_3[ind_1w+N*ind_2x+N*N*ind_3y];
      f_42=f_3[ind_1x+N*ind_2y+N*N*ind_3y];
      f_52=f_3[ind_1y+N*ind_2y+N*N*ind_3y];
      f_62=f_3[ind_1z+N*ind_2y+N*N*ind_3y];
      f_72=f_3[ind_1w+N*ind_2y+N*N*ind_3y];
      f_82=f_3[ind_1x+N*ind_2z+N*N*ind_3y];
      f_92=f_3[ind_1y+N*ind_2z+N*N*ind_3y];
      f_a2=f_3[ind_1z+N*ind_2z+N*N*ind_3y];
      f_b2=f_3[ind_1w+N*ind_2z+N*N*ind_3y];
      f_c2=f_3[ind_1x+N*ind_2w+N*N*ind_3y];
      f_d2=f_3[ind_1y+N*ind_2w+N*N*ind_3y];
      f_e2=f_3[ind_1z+N*ind_2w+N*N*ind_3y];
      f_f2=f_3[ind_1w+N*ind_2w+N*N*ind_3y];

      f_03=f_3[ind_1x+N*ind_2x+N*N*ind_3z];
      f_13=f_3[ind_1y+N*ind_2x+N*N*ind_3z];
      f_23=f_3[ind_1z+N*ind_2x+N*N*ind_3z];
      f_33=f_3[ind_1w+N*ind_2x+N*N*ind_3z];
      f_43=f_3[ind_1x+N*ind_2y+N*N*ind_3z];
      f_53=f_3[ind_1y+N*ind_2y+N*N*ind_3z];
      f_63=f_3[ind_1z+N*ind_2y+N*N*ind_3z];
      f_73=f_3[ind_1w+N*ind_2y+N*N*ind_3z];
      f_83=f_3[ind_1x+N*ind_2z+N*N*ind_3z];
      f_93=f_3[ind_1y+N*ind_2z+N*N*ind_3z];
      f_a3=f_3[ind_1z+N*ind_2z+N*N*ind_3z];
      f_b3=f_3[ind_1w+N*ind_2z+N*N*ind_3z];
      f_c3=f_3[ind_1x+N*ind_2w+N*N*ind_3z];
      f_d3=f_3[ind_1y+N*ind_2w+N*N*ind_3z];
      f_e3=f_3[ind_1z+N*ind_2w+N*N*ind_3z];
      f_f3=f_3[ind_1w+N*ind_2w+N*N*ind_3z];

      f_04=f_3[ind_1x+N*ind_2x+N*N*ind_3w];
      f_14=f_3[ind_1y+N*ind_2x+N*N*ind_3w];
      f_24=f_3[ind_1z+N*ind_2x+N*N*ind_3w];
      f_34=f_3[ind_1w+N*ind_2x+N*N*ind_3w];
      f_44=f_3[ind_1x+N*ind_2y+N*N*ind_3w];
      f_54=f_3[ind_1y+N*ind_2y+N*N*ind_3w];
      f_64=f_3[ind_1z+N*ind_2y+N*N*ind_3w];
      f_74=f_3[ind_1w+N*ind_2y+N*N*ind_3w];
      f_84=f_3[ind_1x+N*ind_2z+N*N*ind_3w];
      f_94=f_3[ind_1y+N*ind_2z+N*N*ind_3w];
      f_a4=f_3[ind_1z+N*ind_2z+N*N*ind_3w];
      f_b4=f_3[ind_1w+N*ind_2z+N*N*ind_3w];
      f_c4=f_3[ind_1x+N*ind_2w+N*N*ind_3w];
      f_d4=f_3[ind_1y+N*ind_2w+N*N*ind_3w];
      f_e4=f_3[ind_1z+N*ind_2w+N*N*ind_3w];
      f_f4=f_3[ind_1w+N*ind_2w+N*N*ind_3w];
      }
 
      while(k3 != -1)
      {
      float s_1_stag = (X_1[k3]+0.5)/dx;
      float s_2_stag = (X_2[k3]+0.5)/dx;       
      float s_3_stag = (X_3[k3]+0.5)/dx;       
      int i_1_stag = convert_int(floor(s_1_stag));
      int i_2_stag = convert_int(floor(s_2_stag));
      int i_3_stag = convert_int(floor(s_3_stag));
      float r_1_stag = s_1_stag-i_1_stag;
      float r_2_stag = s_2_stag-i_2_stag;
      float r_3_stag = s_3_stag-i_3_stag;
      float s_1_c = (X_1[k3]+0.5-dx/2)/dx;
      float s_2_c = (X_2[k3]+0.5-dx/2)/dx;        
      float s_3_c = (X_3[k3]+0.5-dx/2)/dx;        
      int i_1_c = convert_int(floor(s_1_c));
      int i_2_c = convert_int(floor(s_2_c));
      int i_3_c = convert_int(floor(s_3_c));
      float r_1_c = s_1_c-i_1_c;
      float r_2_c = s_2_c-i_2_c;
      float r_3_c = s_3_c-i_3_c;
      
      q1 = sqrt(1.+4.0*r_1_c*(1-r_1_c)); 
      q2 = sqrt(1.+4.0*r_2_c*(1-r_2_c));
      q3 = sqrt(1.+4.0*r_3_stag*(1-r_3_stag));

      v1x = 3.-2.*r_1_c-q1; 
      v1y = 3.-2.*r_1_c+q1; 
      v1z = 1.+2.*r_1_c+q1; 
      v1w = 1.+2.*r_1_c-q1; 
      v1x = v1x/8.;
      v1y = v1y/8.;
      v1z = v1z/8.;
      v1w = v1w/8.;

      v2x = 3.-2.*r_2_c-q2; 
      v2y = 3.-2.*r_2_c+q2; 
      v2z = 1.+2.*r_2_c+q2; 
      v2w = 1.+2.*r_2_c-q2; 
      v2x = v2x/8.;
      v2y = v2y/8.;
      v2z = v2z/8.;
      v2w = v2w/8.;

      v3x = 3.-2.*r_3_stag-q3; 
      v3y = 3.-2.*r_3_stag+q3; 
      v3z = 1.+2.*r_3_stag+q3; 
      v3w = 1.+2.*r_3_stag-q3; 
      v3x = v3x/8.;
      v3y = v3y/8.;
      v3z = v3z/8.;
      v3w = v3w/8.;
      
      ws01 = v1x*v2x*v3x;
      ws11 = v1y*v2x*v3x;
      ws21 = v1z*v2x*v3x;
      ws31 = v1w*v2x*v3x;
      ws41 = v1x*v2y*v3x;
      ws51 = v1y*v2y*v3x;
      ws61 = v1z*v2y*v3x;
      ws71 = v1w*v2y*v3x;
      ws81 = v1x*v2z*v3x;
      ws91 = v1y*v2z*v3x;
      wsa1 = v1z*v2z*v3x;
      wsb1 = v1w*v2z*v3x;
      wsc1 = v1x*v2w*v3x;
      wsd1 = v1y*v2w*v3x;
      wse1 = v1z*v2w*v3x;
      wsf1 = v1w*v2w*v3x;
      
      ws02 = v1x*v2x*v3y;
      ws12 = v1y*v2x*v3y;
      ws22 = v1z*v2x*v3y;
      ws32 = v1w*v2x*v3y;
      ws42 = v1x*v2y*v3y;
      ws52 = v1y*v2y*v3y;
      ws62 = v1z*v2y*v3y;
      ws72 = v1w*v2y*v3y;
      ws82 = v1x*v2z*v3y;
      ws92 = v1y*v2z*v3y;
      wsa2 = v1z*v2z*v3y;
      wsb2 = v1w*v2z*v3y;
      wsc2 = v1x*v2w*v3y;
      wsd2 = v1y*v2w*v3y;
      wse2 = v1z*v2w*v3y;
      wsf2 = v1w*v2w*v3y;

      ws03 = v1x*v2x*v3z;
      ws13 = v1y*v2x*v3z;
      ws23 = v1z*v2x*v3z;
      ws33 = v1w*v2x*v3z;
      ws43 = v1x*v2y*v3z;
      ws53 = v1y*v2y*v3z;
      ws63 = v1z*v2y*v3z;
      ws73 = v1w*v2y*v3z;
      ws83 = v1x*v2z*v3z;
      ws93 = v1y*v2z*v3z;
      wsa3 = v1z*v2z*v3z;
      wsb3 = v1w*v2z*v3z;
      wsc3 = v1x*v2w*v3z;
      wsd3 = v1y*v2w*v3z;
      wse3 = v1z*v2w*v3z;
      wsf3 = v1w*v2w*v3z;

      ws04 = v1x*v2x*v3w;
      ws14 = v1y*v2x*v3w;
      ws24 = v1z*v2x*v3w;
      ws34 = v1w*v2x*v3w;
      ws44 = v1x*v2y*v3w;
      ws54 = v1y*v2y*v3w;
      ws64 = v1z*v2y*v3w;
      ws74 = v1w*v2y*v3w;
      ws84 = v1x*v2z*v3w;
      ws94 = v1y*v2z*v3w;
      wsa4 = v1z*v2z*v3w;
      wsb4 = v1w*v2z*v3w;
      wsc4 = v1x*v2w*v3w;
      wsd4 = v1y*v2w*v3w;
      wse4 = v1z*v2w*v3w;
      wsf4 = v1w*v2w*v3w;

      float my_F_3 = F_3[k3];
      f_01 += c*my_F_3*ws01;
      f_11 += c*my_F_3*ws11;
      f_21 += c*my_F_3*ws21;
      f_31 += c*my_F_3*ws31;
      f_41 += c*my_F_3*ws41;
      f_51 += c*my_F_3*ws51;
      f_61 += c*my_F_3*ws61;
      f_71 += c*my_F_3*ws71;
      f_81 += c*my_F_3*ws81;
      f_91 += c*my_F_3*ws91;
      f_a1 += c*my_F_3*wsa1;
      f_b1 += c*my_F_3*wsb1;
      f_c1 += c*my_F_3*wsc1;
      f_d1 += c*my_F_3*wsd1;
      f_e1 += c*my_F_3*wse1;
      f_f1 += c*my_F_3*wsf1;

      f_02 += c*my_F_3*ws02;
      f_12 += c*my_F_3*ws12;
      f_22 += c*my_F_3*ws22;
      f_32 += c*my_F_3*ws32;
      f_42 += c*my_F_3*ws42;
      f_52 += c*my_F_3*ws52;
      f_62 += c*my_F_3*ws62;
      f_72 += c*my_F_3*ws72;
      f_82 += c*my_F_3*ws82;
      f_92 += c*my_F_3*ws92;
      f_a2 += c*my_F_3*wsa2;
      f_b2 += c*my_F_3*wsb2;
      f_c2 += c*my_F_3*wsc2;
      f_d2 += c*my_F_3*wsd2;
      f_e2 += c*my_F_3*wse2;
      f_f2 += c*my_F_3*wsf2;

      f_03 += c*my_F_3*ws03;
      f_13 += c*my_F_3*ws13;
      f_23 += c*my_F_3*ws23;
      f_33 += c*my_F_3*ws33;
      f_43 += c*my_F_3*ws43;
      f_53 += c*my_F_3*ws53;
      f_63 += c*my_F_3*ws63;
      f_73 += c*my_F_3*ws73;
      f_83 += c*my_F_3*ws83;
      f_93 += c*my_F_3*ws93;
      f_a3 += c*my_F_3*wsa3;
      f_b3 += c*my_F_3*wsb3;
      f_c3 += c*my_F_3*wsc3;
      f_d3 += c*my_F_3*wsd3;
      f_e3 += c*my_F_3*wse3;
      f_f3 += c*my_F_3*wsf3;

      f_04 += c*my_F_3*ws04;
      f_14 += c*my_F_3*ws14;
      f_24 += c*my_F_3*ws24;
      f_34 += c*my_F_3*ws34;
      f_44 += c*my_F_3*ws44;
      f_54 += c*my_F_3*ws54;
      f_64 += c*my_F_3*ws64;
      f_74 += c*my_F_3*ws74;
      f_84 += c*my_F_3*ws84;
      f_94 += c*my_F_3*ws94;
      f_a4 += c*my_F_3*wsa4;
      f_b4 += c*my_F_3*wsb4;
      f_c4 += c*my_F_3*wsc4;
      f_d4 += c*my_F_3*wsd4;
      f_e4 += c*my_F_3*wse4;
      f_f4 += c*my_F_3*wsf4;

      k3 = nextn3[k3];
      if (k3 == -1){
      f_3[ind_1x+N*ind_2x+N*N*ind_3x]=f_01;
      f_3[ind_1y+N*ind_2x+N*N*ind_3x]=f_11;
      f_3[ind_1z+N*ind_2x+N*N*ind_3x]=f_21;
      f_3[ind_1w+N*ind_2x+N*N*ind_3x]=f_31;
      f_3[ind_1x+N*ind_2y+N*N*ind_3x]=f_41;
      f_3[ind_1y+N*ind_2y+N*N*ind_3x]=f_51;
      f_3[ind_1z+N*ind_2y+N*N*ind_3x]=f_61;
      f_3[ind_1w+N*ind_2y+N*N*ind_3x]=f_71;
      f_3[ind_1x+N*ind_2z+N*N*ind_3x]=f_81;
      f_3[ind_1y+N*ind_2z+N*N*ind_3x]=f_91;
      f_3[ind_1z+N*ind_2z+N*N*ind_3x]=f_a1;
      f_3[ind_1w+N*ind_2z+N*N*ind_3x]=f_b1;
      f_3[ind_1x+N*ind_2w+N*N*ind_3x]=f_c1;
      f_3[ind_1y+N*ind_2w+N*N*ind_3x]=f_d1;
      f_3[ind_1z+N*ind_2w+N*N*ind_3x]=f_e1;
      f_3[ind_1w+N*ind_2w+N*N*ind_3x]=f_f1;

      f_3[ind_1x+N*ind_2x+N*N*ind_3y]=f_02;
      f_3[ind_1y+N*ind_2x+N*N*ind_3y]=f_12;
      f_3[ind_1z+N*ind_2x+N*N*ind_3y]=f_22;
      f_3[ind_1w+N*ind_2x+N*N*ind_3y]=f_32;
      f_3[ind_1x+N*ind_2y+N*N*ind_3y]=f_42;
      f_3[ind_1y+N*ind_2y+N*N*ind_3y]=f_52;
      f_3[ind_1z+N*ind_2y+N*N*ind_3y]=f_62;
      f_3[ind_1w+N*ind_2y+N*N*ind_3y]=f_72;
      f_3[ind_1x+N*ind_2z+N*N*ind_3y]=f_82;
      f_3[ind_1y+N*ind_2z+N*N*ind_3y]=f_92;
      f_3[ind_1z+N*ind_2z+N*N*ind_3y]=f_a2;
      f_3[ind_1w+N*ind_2z+N*N*ind_3y]=f_b2;
      f_3[ind_1x+N*ind_2w+N*N*ind_3y]=f_c2;
      f_3[ind_1y+N*ind_2w+N*N*ind_3y]=f_d2;
      f_3[ind_1z+N*ind_2w+N*N*ind_3y]=f_e2;
      f_3[ind_1w+N*ind_2w+N*N*ind_3y]=f_f2;

      f_3[ind_1x+N*ind_2x+N*N*ind_3z]=f_03;
      f_3[ind_1y+N*ind_2x+N*N*ind_3z]=f_13;
      f_3[ind_1z+N*ind_2x+N*N*ind_3z]=f_23;
      f_3[ind_1w+N*ind_2x+N*N*ind_3z]=f_33;
      f_3[ind_1x+N*ind_2y+N*N*ind_3z]=f_43;
      f_3[ind_1y+N*ind_2y+N*N*ind_3z]=f_53;
      f_3[ind_1z+N*ind_2y+N*N*ind_3z]=f_63;
      f_3[ind_1w+N*ind_2y+N*N*ind_3z]=f_73;
      f_3[ind_1x+N*ind_2z+N*N*ind_3z]=f_83;
      f_3[ind_1y+N*ind_2z+N*N*ind_3z]=f_93;
      f_3[ind_1z+N*ind_2z+N*N*ind_3z]=f_a3;
      f_3[ind_1w+N*ind_2z+N*N*ind_3z]=f_b3;
      f_3[ind_1x+N*ind_2w+N*N*ind_3z]=f_c3;
      f_3[ind_1y+N*ind_2w+N*N*ind_3z]=f_d3;
      f_3[ind_1z+N*ind_2w+N*N*ind_3z]=f_e3;
      f_3[ind_1w+N*ind_2w+N*N*ind_3z]=f_f3;

      f_3[ind_1x+N*ind_2x+N*N*ind_3w]=f_04;
      f_3[ind_1y+N*ind_2x+N*N*ind_3w]=f_14;
      f_3[ind_1z+N*ind_2x+N*N*ind_3w]=f_24;
      f_3[ind_1w+N*ind_2x+N*N*ind_3w]=f_34;
      f_3[ind_1x+N*ind_2y+N*N*ind_3w]=f_44;
      f_3[ind_1y+N*ind_2y+N*N*ind_3w]=f_54;
      f_3[ind_1z+N*ind_2y+N*N*ind_3w]=f_64;
      f_3[ind_1w+N*ind_2y+N*N*ind_3w]=f_74;
      f_3[ind_1x+N*ind_2z+N*N*ind_3w]=f_84;
      f_3[ind_1y+N*ind_2z+N*N*ind_3w]=f_94;
      f_3[ind_1z+N*ind_2z+N*N*ind_3w]=f_a4;
      f_3[ind_1w+N*ind_2z+N*N*ind_3w]=f_b4;
      f_3[ind_1x+N*ind_2w+N*N*ind_3w]=f_c4;
      f_3[ind_1y+N*ind_2w+N*N*ind_3w]=f_d4;
      f_3[ind_1z+N*ind_2w+N*N*ind_3w]=f_e4;
      f_3[ind_1w+N*ind_2w+N*N*ind_3w]=f_f4;
      }
      }
    }
    __kernel void interp(__global const float *u_1, __global const float *u_2, __global const float *u_3, __global const float *X_1, __global const float *X_2, __global const float *X_3, const unsigned N, const float dx, __global float *U_1, __global float *U_2, __global float *U_3)
    {
      unsigned k = get_global_id(0);
      float s_1_stag = (X_1[k]+0.5)/dx;
      float s_2_stag = (X_2[k]+0.5)/dx;       
      float s_3_stag = (X_3[k]+0.5)/dx;       
      int i_1_stag = convert_int(floor(s_1_stag));
      int i_2_stag = convert_int(floor(s_2_stag));
      int i_3_stag = convert_int(floor(s_3_stag));
      float r_1_stag = s_1_stag-i_1_stag;
      float r_2_stag = s_2_stag-i_2_stag;
      float r_3_stag = s_3_stag-i_3_stag;
      float s_1_c = (X_1[k]+0.5-dx/2)/dx;
      float s_2_c = (X_2[k]+0.5-dx/2)/dx;        
      float s_3_c = (X_3[k]+0.5-dx/2)/dx;        
      int i_1_c = convert_int(floor(s_1_c));
      int i_2_c = convert_int(floor(s_2_c));
      int i_3_c = convert_int(floor(s_3_c));
      float r_1_c = s_1_c-i_1_c;
      float r_2_c = s_2_c-i_2_c;
      float r_3_c = s_3_c-i_3_c;

      int ind_1x, ind_1y, ind_1z, ind_1w;
      int ind_2x, ind_2y, ind_2z, ind_2w;
      int ind_3x, ind_3y, ind_3z, ind_3w;
      ind_1x = (i_1_stag-1 & N-1);
      ind_1y = (i_1_stag & N-1);
      ind_1z = (i_1_stag+1 & N-1);
      ind_1w = (i_1_stag+2 & N-1);

      ind_2x = (i_2_c-1 & N-1);
      ind_2y = (i_2_c & N-1);
      ind_2z = (i_2_c+1 & N-1);
      ind_2w = (i_2_c+2 & N-1);

      ind_3x = (i_3_c-1 & N-1);
      ind_3y = (i_3_c & N-1);
      ind_3z = (i_3_c+1 & N-1);
      ind_3w = (i_3_c+2 & N-1);

      float sb_tests01, sb_tests11, sb_tests21, sb_tests31;
      float sb_tests41, sb_tests51, sb_tests61, sb_tests71;
      float sb_tests81, sb_tests91, sb_testsa1, sb_testsb1;
      float sb_testsc1, sb_testsd1, sb_testse1, sb_testsf1;

      float sb_tests02, sb_tests12, sb_tests22, sb_tests32;
      float sb_tests42, sb_tests52, sb_tests62, sb_tests72;
      float sb_tests82, sb_tests92, sb_testsa2, sb_testsb2;
      float sb_testsc2, sb_testsd2, sb_testse2, sb_testsf2;

      float sb_tests03, sb_tests13, sb_tests23, sb_tests33;
      float sb_tests43, sb_tests53, sb_tests63, sb_tests73;
      float sb_tests83, sb_tests93, sb_testsa3, sb_testsb3;
      float sb_testsc3, sb_testsd3, sb_testse3, sb_testsf3;

      float sb_tests04, sb_tests14, sb_tests24, sb_tests34;
      float sb_tests44, sb_tests54, sb_tests64, sb_tests74;
      float sb_tests84, sb_tests94, sb_testsa4, sb_testsb4;
      float sb_testsc4, sb_testsd4, sb_testse4, sb_testsf4;

      sb_tests01 = u_1[ind_1x+N*ind_2x+N*N*ind_3x];
      sb_tests11 = u_1[ind_1y+N*ind_2x+N*N*ind_3x];
      sb_tests21 = u_1[ind_1z+N*ind_2x+N*N*ind_3x];
      sb_tests31 = u_1[ind_1w+N*ind_2x+N*N*ind_3x];
      sb_tests41 = u_1[ind_1x+N*ind_2y+N*N*ind_3x];
      sb_tests51 = u_1[ind_1y+N*ind_2y+N*N*ind_3x];
      sb_tests61 = u_1[ind_1z+N*ind_2y+N*N*ind_3x];
      sb_tests71 = u_1[ind_1w+N*ind_2y+N*N*ind_3x];
      sb_tests81 = u_1[ind_1x+N*ind_2z+N*N*ind_3x];
      sb_tests91 = u_1[ind_1y+N*ind_2z+N*N*ind_3x];
      sb_testsa1 = u_1[ind_1z+N*ind_2z+N*N*ind_3x];
      sb_testsb1 = u_1[ind_1w+N*ind_2z+N*N*ind_3x];
      sb_testsc1 = u_1[ind_1x+N*ind_2w+N*N*ind_3x];
      sb_testsd1 = u_1[ind_1y+N*ind_2w+N*N*ind_3x];
      sb_testse1 = u_1[ind_1z+N*ind_2w+N*N*ind_3x];
      sb_testsf1 = u_1[ind_1w+N*ind_2w+N*N*ind_3x];

      sb_tests02 = u_1[ind_1x+N*ind_2x+N*N*ind_3y];
      sb_tests12 = u_1[ind_1y+N*ind_2x+N*N*ind_3y];
      sb_tests22 = u_1[ind_1z+N*ind_2x+N*N*ind_3y];
      sb_tests32 = u_1[ind_1w+N*ind_2x+N*N*ind_3y];
      sb_tests42 = u_1[ind_1x+N*ind_2y+N*N*ind_3y];
      sb_tests52 = u_1[ind_1y+N*ind_2y+N*N*ind_3y];
      sb_tests62 = u_1[ind_1z+N*ind_2y+N*N*ind_3y];
      sb_tests72 = u_1[ind_1w+N*ind_2y+N*N*ind_3y];
      sb_tests82 = u_1[ind_1x+N*ind_2z+N*N*ind_3y];
      sb_tests92 = u_1[ind_1y+N*ind_2z+N*N*ind_3y];
      sb_testsa2 = u_1[ind_1z+N*ind_2z+N*N*ind_3y];
      sb_testsb2 = u_1[ind_1w+N*ind_2z+N*N*ind_3y];
      sb_testsc2 = u_1[ind_1x+N*ind_2w+N*N*ind_3y];
      sb_testsd2 = u_1[ind_1y+N*ind_2w+N*N*ind_3y];
      sb_testse2 = u_1[ind_1z+N*ind_2w+N*N*ind_3y];
      sb_testsf2 = u_1[ind_1w+N*ind_2w+N*N*ind_3y];

      sb_tests03 = u_1[ind_1x+N*ind_2x+N*N*ind_3z];
      sb_tests13 = u_1[ind_1y+N*ind_2x+N*N*ind_3z];
      sb_tests23 = u_1[ind_1z+N*ind_2x+N*N*ind_3z];
      sb_tests33 = u_1[ind_1w+N*ind_2x+N*N*ind_3z];
      sb_tests43 = u_1[ind_1x+N*ind_2y+N*N*ind_3z];
      sb_tests53 = u_1[ind_1y+N*ind_2y+N*N*ind_3z];
      sb_tests63 = u_1[ind_1z+N*ind_2y+N*N*ind_3z];
      sb_tests73 = u_1[ind_1w+N*ind_2y+N*N*ind_3z];
      sb_tests83 = u_1[ind_1x+N*ind_2z+N*N*ind_3z];
      sb_tests93 = u_1[ind_1y+N*ind_2z+N*N*ind_3z];
      sb_testsa3 = u_1[ind_1z+N*ind_2z+N*N*ind_3z];
      sb_testsb3 = u_1[ind_1w+N*ind_2z+N*N*ind_3z];
      sb_testsc3 = u_1[ind_1x+N*ind_2w+N*N*ind_3z];
      sb_testsd3 = u_1[ind_1y+N*ind_2w+N*N*ind_3z];
      sb_testse3 = u_1[ind_1z+N*ind_2w+N*N*ind_3z];
      sb_testsf3 = u_1[ind_1w+N*ind_2w+N*N*ind_3z];

      sb_tests04 = u_1[ind_1x+N*ind_2x+N*N*ind_3w];
      sb_tests14 = u_1[ind_1y+N*ind_2x+N*N*ind_3w];
      sb_tests24 = u_1[ind_1z+N*ind_2x+N*N*ind_3w];
      sb_tests34 = u_1[ind_1w+N*ind_2x+N*N*ind_3w];
      sb_tests44 = u_1[ind_1x+N*ind_2y+N*N*ind_3w];
      sb_tests54 = u_1[ind_1y+N*ind_2y+N*N*ind_3w];
      sb_tests64 = u_1[ind_1z+N*ind_2y+N*N*ind_3w];
      sb_tests74 = u_1[ind_1w+N*ind_2y+N*N*ind_3w];
      sb_tests84 = u_1[ind_1x+N*ind_2z+N*N*ind_3w];
      sb_tests94 = u_1[ind_1y+N*ind_2z+N*N*ind_3w];
      sb_testsa4 = u_1[ind_1z+N*ind_2z+N*N*ind_3w];
      sb_testsb4 = u_1[ind_1w+N*ind_2z+N*N*ind_3w];
      sb_testsc4 = u_1[ind_1x+N*ind_2w+N*N*ind_3w];
      sb_testsd4 = u_1[ind_1y+N*ind_2w+N*N*ind_3w];
      sb_testse4 = u_1[ind_1z+N*ind_2w+N*N*ind_3w];
      sb_testsf4 = u_1[ind_1w+N*ind_2w+N*N*ind_3w];

      float q1 = sqrt(1.+4.0*r_1_stag*(1-r_1_stag)); 
      float q2 = sqrt(1.+4.0*r_2_c*(1-r_2_c));
      float q3 = sqrt(1.+4.0*r_3_c*(1-r_3_c));

      float v1x, v1y, v1z, v1w;
      float v2x, v2y, v2z, v2w;
      float v3x, v3y, v3z, v3w;

      v1x = 3.-2.*r_1_stag-q1; 
      v1y = 3.-2.*r_1_stag+q1; 
      v1z = 1.+2.*r_1_stag+q1; 
      v1w = 1.+2.*r_1_stag-q1; 
      v1x = v1x/8.;
      v1y = v1y/8.;
      v1z = v1z/8.;
      v1w = v1w/8.;

      v2x = 3.-2.*r_2_c-q2; 
      v2y = 3.-2.*r_2_c+q2; 
      v2z = 1.+2.*r_2_c+q2; 
      v2w = 1.+2.*r_2_c-q2; 
      v2x = v2x/8.;
      v2y = v2y/8.;
      v2z = v2z/8.;
      v2w = v2w/8.;

      v3x = 3.-2.*r_3_c-q3; 
      v3y = 3.-2.*r_3_c+q3; 
      v3z = 1.+2.*r_3_c+q3; 
      v3w = 1.+2.*r_3_c-q3; 
      v3x = v3x/8.;
      v3y = v3y/8.;
      v3z = v3z/8.;
      v3w = v3w/8.;
      
      float ws01, ws11, ws21, ws31;
      float ws41, ws51, ws61, ws71;
      float ws81, ws91, wsa1, wsb1;
      float wsc1, wsd1, wse1, wsf1;

      float ws02, ws12, ws22, ws32;
      float ws42, ws52, ws62, ws72;
      float ws82, ws92, wsa2, wsb2;
      float wsc2, wsd2, wse2, wsf2;

      float ws03, ws13, ws23, ws33;
      float ws43, ws53, ws63, ws73;
      float ws83, ws93, wsa3, wsb3;
      float wsc3, wsd3, wse3, wsf3;

      float ws04, ws14, ws24, ws34;
      float ws44, ws54, ws64, ws74;
      float ws84, ws94, wsa4, wsb4;
      float wsc4, wsd4, wse4, wsf4;

      ws01 = v1x*v2x*v3x;
      ws11 = v1y*v2x*v3x;
      ws21 = v1z*v2x*v3x;
      ws31 = v1w*v2x*v3x;
      ws41 = v1x*v2y*v3x;
      ws51 = v1y*v2y*v3x;
      ws61 = v1z*v2y*v3x;
      ws71 = v1w*v2y*v3x;
      ws81 = v1x*v2z*v3x;
      ws91 = v1y*v2z*v3x;
      wsa1 = v1z*v2z*v3x;
      wsb1 = v1w*v2z*v3x;
      wsc1 = v1x*v2w*v3x;
      wsd1 = v1y*v2w*v3x;
      wse1 = v1z*v2w*v3x;
      wsf1 = v1w*v2w*v3x;
      
      ws02 = v1x*v2x*v3y;
      ws12 = v1y*v2x*v3y;
      ws22 = v1z*v2x*v3y;
      ws32 = v1w*v2x*v3y;
      ws42 = v1x*v2y*v3y;
      ws52 = v1y*v2y*v3y;
      ws62 = v1z*v2y*v3y;
      ws72 = v1w*v2y*v3y;
      ws82 = v1x*v2z*v3y;
      ws92 = v1y*v2z*v3y;
      wsa2 = v1z*v2z*v3y;
      wsb2 = v1w*v2z*v3y;
      wsc2 = v1x*v2w*v3y;
      wsd2 = v1y*v2w*v3y;
      wse2 = v1z*v2w*v3y;
      wsf2 = v1w*v2w*v3y;

      ws03 = v1x*v2x*v3z;
      ws13 = v1y*v2x*v3z;
      ws23 = v1z*v2x*v3z;
      ws33 = v1w*v2x*v3z;
      ws43 = v1x*v2y*v3z;
      ws53 = v1y*v2y*v3z;
      ws63 = v1z*v2y*v3z;
      ws73 = v1w*v2y*v3z;
      ws83 = v1x*v2z*v3z;
      ws93 = v1y*v2z*v3z;
      wsa3 = v1z*v2z*v3z;
      wsb3 = v1w*v2z*v3z;
      wsc3 = v1x*v2w*v3z;
      wsd3 = v1y*v2w*v3z;
      wse3 = v1z*v2w*v3z;
      wsf3 = v1w*v2w*v3z;

      ws04 = v1x*v2x*v3w;
      ws14 = v1y*v2x*v3w;
      ws24 = v1z*v2x*v3w;
      ws34 = v1w*v2x*v3w;
      ws44 = v1x*v2y*v3w;
      ws54 = v1y*v2y*v3w;
      ws64 = v1z*v2y*v3w;
      ws74 = v1w*v2y*v3w;
      ws84 = v1x*v2z*v3w;
      ws94 = v1y*v2z*v3w;
      wsa4 = v1z*v2z*v3w;
      wsb4 = v1w*v2z*v3w;
      wsc4 = v1x*v2w*v3w;
      wsd4 = v1y*v2w*v3w;
      wse4 = v1z*v2w*v3w;
      wsf4 = v1w*v2w*v3w;

      ws01 = ws01*sb_tests01;
      ws11 = ws11*sb_tests11;
      ws21 = ws21*sb_tests21;
      ws31 = ws31*sb_tests31;
      ws41 = ws41*sb_tests41;
      ws51 = ws51*sb_tests51;
      ws61 = ws61*sb_tests61;
      ws71 = ws71*sb_tests71;
      ws81 = ws81*sb_tests81;
      ws91 = ws91*sb_tests91;
      wsa1 = wsa1*sb_testsa1;
      wsb1 = wsb1*sb_testsb1;
      wsc1 = wsc1*sb_testsc1;
      wsd1 = wsd1*sb_testsd1;
      wse1 = wse1*sb_testse1;
      wsf1 = wsf1*sb_testsf1;

      ws02 = ws02*sb_tests02;
      ws12 = ws12*sb_tests12;
      ws22 = ws22*sb_tests22;
      ws32 = ws32*sb_tests32;
      ws42 = ws42*sb_tests42;
      ws52 = ws52*sb_tests52;
      ws62 = ws62*sb_tests62;
      ws72 = ws72*sb_tests72;
      ws82 = ws82*sb_tests82;
      ws92 = ws92*sb_tests92;
      wsa2 = wsa2*sb_testsa2;
      wsb2 = wsb2*sb_testsb2;
      wsc2 = wsc2*sb_testsc2;
      wsd2 = wsd2*sb_testsd2;
      wse2 = wse2*sb_testse2;
      wsf2 = wsf2*sb_testsf2;

      ws03 = ws03*sb_tests03;
      ws13 = ws13*sb_tests13;
      ws23 = ws23*sb_tests23;
      ws33 = ws33*sb_tests33;
      ws43 = ws43*sb_tests43;
      ws53 = ws53*sb_tests53;
      ws63 = ws63*sb_tests63;
      ws73 = ws73*sb_tests73;
      ws83 = ws83*sb_tests83;
      ws93 = ws93*sb_tests93;
      wsa3 = wsa3*sb_testsa3;
      wsb3 = wsb3*sb_testsb3;
      wsc3 = wsc3*sb_testsc3;
      wsd3 = wsd3*sb_testsd3;
      wse3 = wse3*sb_testse3;
      wsf3 = wsf3*sb_testsf3;

      ws04 = ws04*sb_tests04;
      ws14 = ws14*sb_tests14;
      ws24 = ws24*sb_tests24;
      ws34 = ws34*sb_tests34;
      ws44 = ws44*sb_tests44;
      ws54 = ws54*sb_tests54;
      ws64 = ws64*sb_tests64;
      ws74 = ws74*sb_tests74;
      ws84 = ws84*sb_tests84;
      ws94 = ws94*sb_tests94;
      wsa4 = wsa4*sb_testsa4;
      wsb4 = wsb4*sb_testsb4;
      wsc4 = wsc4*sb_testsc4;
      wsd4 = wsd4*sb_testsd4;
      wse4 = wse4*sb_testse4;
      wsf4 = wsf4*sb_testsf4;

      U_1[k] = ws01+ws11+ws21+ws31
	       +ws41+ws51+ws61+ws71
	       +ws81+ws91+wsa1+wsb1
	       +wsc1+wsd1+wse1+wsf1
               +ws02+ws12+ws22+ws32
	       +ws42+ws52+ws62+ws72
	       +ws82+ws92+wsa2+wsb2
	       +wsc2+wsd2+wse2+wsf2
               +ws03+ws13+ws23+ws33
	       +ws43+ws53+ws63+ws73
	       +ws83+ws93+wsa3+wsb3
	       +wsc3+wsd3+wse3+wsf3
               +ws04+ws14+ws24+ws34
	       +ws44+ws54+ws64+ws74
	       +ws84+ws94+wsa4+wsb4
	       +wsc4+wsd4+wse4+wsf4;

      ind_1x = (i_1_c-1 & N-1);
      ind_1y = (i_1_c & N-1);
      ind_1z = (i_1_c+1 & N-1);
      ind_1w = (i_1_c+2 & N-1);

      ind_2x = (i_2_stag-1 & N-1);
      ind_2y = (i_2_stag & N-1);
      ind_2z = (i_2_stag+1 & N-1);
      ind_2w = (i_2_stag+2 & N-1);

      ind_3x = (i_3_c-1 & N-1);
      ind_3y = (i_3_c & N-1);
      ind_3z = (i_3_c+1 & N-1);
      ind_3w = (i_3_c+2 & N-1);

      sb_tests01 = u_2[ind_1x+N*ind_2x+N*N*ind_3x];
      sb_tests11 = u_2[ind_1y+N*ind_2x+N*N*ind_3x];
      sb_tests21 = u_2[ind_1z+N*ind_2x+N*N*ind_3x];
      sb_tests31 = u_2[ind_1w+N*ind_2x+N*N*ind_3x];
      sb_tests41 = u_2[ind_1x+N*ind_2y+N*N*ind_3x];
      sb_tests51 = u_2[ind_1y+N*ind_2y+N*N*ind_3x];
      sb_tests61 = u_2[ind_1z+N*ind_2y+N*N*ind_3x];
      sb_tests71 = u_2[ind_1w+N*ind_2y+N*N*ind_3x];
      sb_tests81 = u_2[ind_1x+N*ind_2z+N*N*ind_3x];
      sb_tests91 = u_2[ind_1y+N*ind_2z+N*N*ind_3x];
      sb_testsa1 = u_2[ind_1z+N*ind_2z+N*N*ind_3x];
      sb_testsb1 = u_2[ind_1w+N*ind_2z+N*N*ind_3x];
      sb_testsc1 = u_2[ind_1x+N*ind_2w+N*N*ind_3x];
      sb_testsd1 = u_2[ind_1y+N*ind_2w+N*N*ind_3x];
      sb_testse1 = u_2[ind_1z+N*ind_2w+N*N*ind_3x];
      sb_testsf1 = u_2[ind_1w+N*ind_2w+N*N*ind_3x];

      sb_tests02 = u_2[ind_1x+N*ind_2x+N*N*ind_3y];
      sb_tests12 = u_2[ind_1y+N*ind_2x+N*N*ind_3y];
      sb_tests22 = u_2[ind_1z+N*ind_2x+N*N*ind_3y];
      sb_tests32 = u_2[ind_1w+N*ind_2x+N*N*ind_3y];
      sb_tests42 = u_2[ind_1x+N*ind_2y+N*N*ind_3y];
      sb_tests52 = u_2[ind_1y+N*ind_2y+N*N*ind_3y];
      sb_tests62 = u_2[ind_1z+N*ind_2y+N*N*ind_3y];
      sb_tests72 = u_2[ind_1w+N*ind_2y+N*N*ind_3y];
      sb_tests82 = u_2[ind_1x+N*ind_2z+N*N*ind_3y];
      sb_tests92 = u_2[ind_1y+N*ind_2z+N*N*ind_3y];
      sb_testsa2 = u_2[ind_1z+N*ind_2z+N*N*ind_3y];
      sb_testsb2 = u_2[ind_1w+N*ind_2z+N*N*ind_3y];
      sb_testsc2 = u_2[ind_1x+N*ind_2w+N*N*ind_3y];
      sb_testsd2 = u_2[ind_1y+N*ind_2w+N*N*ind_3y];
      sb_testse2 = u_2[ind_1z+N*ind_2w+N*N*ind_3y];
      sb_testsf2 = u_2[ind_1w+N*ind_2w+N*N*ind_3y];

      sb_tests03 = u_2[ind_1x+N*ind_2x+N*N*ind_3z];
      sb_tests13 = u_2[ind_1y+N*ind_2x+N*N*ind_3z];
      sb_tests23 = u_2[ind_1z+N*ind_2x+N*N*ind_3z];
      sb_tests33 = u_2[ind_1w+N*ind_2x+N*N*ind_3z];
      sb_tests43 = u_2[ind_1x+N*ind_2y+N*N*ind_3z];
      sb_tests53 = u_2[ind_1y+N*ind_2y+N*N*ind_3z];
      sb_tests63 = u_2[ind_1z+N*ind_2y+N*N*ind_3z];
      sb_tests73 = u_2[ind_1w+N*ind_2y+N*N*ind_3z];
      sb_tests83 = u_2[ind_1x+N*ind_2z+N*N*ind_3z];
      sb_tests93 = u_2[ind_1y+N*ind_2z+N*N*ind_3z];
      sb_testsa3 = u_2[ind_1z+N*ind_2z+N*N*ind_3z];
      sb_testsb3 = u_2[ind_1w+N*ind_2z+N*N*ind_3z];
      sb_testsc3 = u_2[ind_1x+N*ind_2w+N*N*ind_3z];
      sb_testsd3 = u_2[ind_1y+N*ind_2w+N*N*ind_3z];
      sb_testse3 = u_2[ind_1z+N*ind_2w+N*N*ind_3z];
      sb_testsf3 = u_2[ind_1w+N*ind_2w+N*N*ind_3z];

      sb_tests04 = u_2[ind_1x+N*ind_2x+N*N*ind_3w];
      sb_tests14 = u_2[ind_1y+N*ind_2x+N*N*ind_3w];
      sb_tests24 = u_2[ind_1z+N*ind_2x+N*N*ind_3w];
      sb_tests34 = u_2[ind_1w+N*ind_2x+N*N*ind_3w];
      sb_tests44 = u_2[ind_1x+N*ind_2y+N*N*ind_3w];
      sb_tests54 = u_2[ind_1y+N*ind_2y+N*N*ind_3w];
      sb_tests64 = u_2[ind_1z+N*ind_2y+N*N*ind_3w];
      sb_tests74 = u_2[ind_1w+N*ind_2y+N*N*ind_3w];
      sb_tests84 = u_2[ind_1x+N*ind_2z+N*N*ind_3w];
      sb_tests94 = u_2[ind_1y+N*ind_2z+N*N*ind_3w];
      sb_testsa4 = u_2[ind_1z+N*ind_2z+N*N*ind_3w];
      sb_testsb4 = u_2[ind_1w+N*ind_2z+N*N*ind_3w];
      sb_testsc4 = u_2[ind_1x+N*ind_2w+N*N*ind_3w];
      sb_testsd4 = u_2[ind_1y+N*ind_2w+N*N*ind_3w];
      sb_testse4 = u_2[ind_1z+N*ind_2w+N*N*ind_3w];
      sb_testsf4 = u_2[ind_1w+N*ind_2w+N*N*ind_3w];

      q1 = sqrt(1.+4.0*r_1_c*(1-r_1_c)); 
      q2 = sqrt(1.+4.0*r_2_stag*(1-r_2_stag));
      q3 = sqrt(1.+4.0*r_3_c*(1-r_3_c));

      v1x = 3.-2.*r_1_c-q1; 
      v1y = 3.-2.*r_1_c+q1; 
      v1z = 1.+2.*r_1_c+q1; 
      v1w = 1.+2.*r_1_c-q1; 
      v1x = v1x/8.;
      v1y = v1y/8.;
      v1z = v1z/8.;
      v1w = v1w/8.;

      v2x = 3.-2.*r_2_stag-q2; 
      v2y = 3.-2.*r_2_stag+q2; 
      v2z = 1.+2.*r_2_stag+q2; 
      v2w = 1.+2.*r_2_stag-q2; 
      v2x = v2x/8.;
      v2y = v2y/8.;
      v2z = v2z/8.;
      v2w = v2w/8.;

      v3x = 3.-2.*r_3_c-q3; 
      v3y = 3.-2.*r_3_c+q3; 
      v3z = 1.+2.*r_3_c+q3; 
      v3w = 1.+2.*r_3_c-q3; 
      v3x = v3x/8.;
      v3y = v3y/8.;
      v3z = v3z/8.;
      v3w = v3w/8.;
      
      ws01 = v1x*v2x*v3x;
      ws11 = v1y*v2x*v3x;
      ws21 = v1z*v2x*v3x;
      ws31 = v1w*v2x*v3x;
      ws41 = v1x*v2y*v3x;
      ws51 = v1y*v2y*v3x;
      ws61 = v1z*v2y*v3x;
      ws71 = v1w*v2y*v3x;
      ws81 = v1x*v2z*v3x;
      ws91 = v1y*v2z*v3x;
      wsa1 = v1z*v2z*v3x;
      wsb1 = v1w*v2z*v3x;
      wsc1 = v1x*v2w*v3x;
      wsd1 = v1y*v2w*v3x;
      wse1 = v1z*v2w*v3x;
      wsf1 = v1w*v2w*v3x;
      
      ws02 = v1x*v2x*v3y;
      ws12 = v1y*v2x*v3y;
      ws22 = v1z*v2x*v3y;
      ws32 = v1w*v2x*v3y;
      ws42 = v1x*v2y*v3y;
      ws52 = v1y*v2y*v3y;
      ws62 = v1z*v2y*v3y;
      ws72 = v1w*v2y*v3y;
      ws82 = v1x*v2z*v3y;
      ws92 = v1y*v2z*v3y;
      wsa2 = v1z*v2z*v3y;
      wsb2 = v1w*v2z*v3y;
      wsc2 = v1x*v2w*v3y;
      wsd2 = v1y*v2w*v3y;
      wse2 = v1z*v2w*v3y;
      wsf2 = v1w*v2w*v3y;

      ws03 = v1x*v2x*v3z;
      ws13 = v1y*v2x*v3z;
      ws23 = v1z*v2x*v3z;
      ws33 = v1w*v2x*v3z;
      ws43 = v1x*v2y*v3z;
      ws53 = v1y*v2y*v3z;
      ws63 = v1z*v2y*v3z;
      ws73 = v1w*v2y*v3z;
      ws83 = v1x*v2z*v3z;
      ws93 = v1y*v2z*v3z;
      wsa3 = v1z*v2z*v3z;
      wsb3 = v1w*v2z*v3z;
      wsc3 = v1x*v2w*v3z;
      wsd3 = v1y*v2w*v3z;
      wse3 = v1z*v2w*v3z;
      wsf3 = v1w*v2w*v3z;

      ws04 = v1x*v2x*v3w;
      ws14 = v1y*v2x*v3w;
      ws24 = v1z*v2x*v3w;
      ws34 = v1w*v2x*v3w;
      ws44 = v1x*v2y*v3w;
      ws54 = v1y*v2y*v3w;
      ws64 = v1z*v2y*v3w;
      ws74 = v1w*v2y*v3w;
      ws84 = v1x*v2z*v3w;
      ws94 = v1y*v2z*v3w;
      wsa4 = v1z*v2z*v3w;
      wsb4 = v1w*v2z*v3w;
      wsc4 = v1x*v2w*v3w;
      wsd4 = v1y*v2w*v3w;
      wse4 = v1z*v2w*v3w;
      wsf4 = v1w*v2w*v3w;

      ws01 = ws01*sb_tests01;
      ws11 = ws11*sb_tests11;
      ws21 = ws21*sb_tests21;
      ws31 = ws31*sb_tests31;
      ws41 = ws41*sb_tests41;
      ws51 = ws51*sb_tests51;
      ws61 = ws61*sb_tests61;
      ws71 = ws71*sb_tests71;
      ws81 = ws81*sb_tests81;
      ws91 = ws91*sb_tests91;
      wsa1 = wsa1*sb_testsa1;
      wsb1 = wsb1*sb_testsb1;
      wsc1 = wsc1*sb_testsc1;
      wsd1 = wsd1*sb_testsd1;
      wse1 = wse1*sb_testse1;
      wsf1 = wsf1*sb_testsf1;

      ws02 = ws02*sb_tests02;
      ws12 = ws12*sb_tests12;
      ws22 = ws22*sb_tests22;
      ws32 = ws32*sb_tests32;
      ws42 = ws42*sb_tests42;
      ws52 = ws52*sb_tests52;
      ws62 = ws62*sb_tests62;
      ws72 = ws72*sb_tests72;
      ws82 = ws82*sb_tests82;
      ws92 = ws92*sb_tests92;
      wsa2 = wsa2*sb_testsa2;
      wsb2 = wsb2*sb_testsb2;
      wsc2 = wsc2*sb_testsc2;
      wsd2 = wsd2*sb_testsd2;
      wse2 = wse2*sb_testse2;
      wsf2 = wsf2*sb_testsf2;

      ws03 = ws03*sb_tests03;
      ws13 = ws13*sb_tests13;
      ws23 = ws23*sb_tests23;
      ws33 = ws33*sb_tests33;
      ws43 = ws43*sb_tests43;
      ws53 = ws53*sb_tests53;
      ws63 = ws63*sb_tests63;
      ws73 = ws73*sb_tests73;
      ws83 = ws83*sb_tests83;
      ws93 = ws93*sb_tests93;
      wsa3 = wsa3*sb_testsa3;
      wsb3 = wsb3*sb_testsb3;
      wsc3 = wsc3*sb_testsc3;
      wsd3 = wsd3*sb_testsd3;
      wse3 = wse3*sb_testse3;
      wsf3 = wsf3*sb_testsf3;

      ws04 = ws04*sb_tests04;
      ws14 = ws14*sb_tests14;
      ws24 = ws24*sb_tests24;
      ws34 = ws34*sb_tests34;
      ws44 = ws44*sb_tests44;
      ws54 = ws54*sb_tests54;
      ws64 = ws64*sb_tests64;
      ws74 = ws74*sb_tests74;
      ws84 = ws84*sb_tests84;
      ws94 = ws94*sb_tests94;
      wsa4 = wsa4*sb_testsa4;
      wsb4 = wsb4*sb_testsb4;
      wsc4 = wsc4*sb_testsc4;
      wsd4 = wsd4*sb_testsd4;
      wse4 = wse4*sb_testse4;
      wsf4 = wsf4*sb_testsf4;

      U_2[k] = ws01+ws11+ws21+ws31
	       +ws41+ws51+ws61+ws71
	       +ws81+ws91+wsa1+wsb1
	       +wsc1+wsd1+wse1+wsf1
               +ws02+ws12+ws22+ws32
	       +ws42+ws52+ws62+ws72
	       +ws82+ws92+wsa2+wsb2
	       +wsc2+wsd2+wse2+wsf2
               +ws03+ws13+ws23+ws33
	       +ws43+ws53+ws63+ws73
	       +ws83+ws93+wsa3+wsb3
	       +wsc3+wsd3+wse3+wsf3
               +ws04+ws14+ws24+ws34
	       +ws44+ws54+ws64+ws74
	       +ws84+ws94+wsa4+wsb4
	       +wsc4+wsd4+wse4+wsf4;

      ind_1x = (i_1_c-1 & N-1);
      ind_1y = (i_1_c & N-1);
      ind_1z = (i_1_c+1 & N-1);
      ind_1w = (i_1_c+2 & N-1);

      ind_2x = (i_2_c-1 & N-1);
      ind_2y = (i_2_c & N-1);
      ind_2z = (i_2_c+1 & N-1);
      ind_2w = (i_2_c+2 & N-1);

      ind_3x = (i_3_stag-1 & N-1);
      ind_3y = (i_3_stag & N-1);
      ind_3z = (i_3_stag+1 & N-1);
      ind_3w = (i_3_stag+2 & N-1);

      sb_tests01 = u_3[ind_1x+N*ind_2x+N*N*ind_3x];
      sb_tests11 = u_3[ind_1y+N*ind_2x+N*N*ind_3x];
      sb_tests21 = u_3[ind_1z+N*ind_2x+N*N*ind_3x];
      sb_tests31 = u_3[ind_1w+N*ind_2x+N*N*ind_3x];
      sb_tests41 = u_3[ind_1x+N*ind_2y+N*N*ind_3x];
      sb_tests51 = u_3[ind_1y+N*ind_2y+N*N*ind_3x];
      sb_tests61 = u_3[ind_1z+N*ind_2y+N*N*ind_3x];
      sb_tests71 = u_3[ind_1w+N*ind_2y+N*N*ind_3x];
      sb_tests81 = u_3[ind_1x+N*ind_2z+N*N*ind_3x];
      sb_tests91 = u_3[ind_1y+N*ind_2z+N*N*ind_3x];
      sb_testsa1 = u_3[ind_1z+N*ind_2z+N*N*ind_3x];
      sb_testsb1 = u_3[ind_1w+N*ind_2z+N*N*ind_3x];
      sb_testsc1 = u_3[ind_1x+N*ind_2w+N*N*ind_3x];
      sb_testsd1 = u_3[ind_1y+N*ind_2w+N*N*ind_3x];
      sb_testse1 = u_3[ind_1z+N*ind_2w+N*N*ind_3x];
      sb_testsf1 = u_3[ind_1w+N*ind_2w+N*N*ind_3x];

      sb_tests02 = u_3[ind_1x+N*ind_2x+N*N*ind_3y];
      sb_tests12 = u_3[ind_1y+N*ind_2x+N*N*ind_3y];
      sb_tests22 = u_3[ind_1z+N*ind_2x+N*N*ind_3y];
      sb_tests32 = u_3[ind_1w+N*ind_2x+N*N*ind_3y];
      sb_tests42 = u_3[ind_1x+N*ind_2y+N*N*ind_3y];
      sb_tests52 = u_3[ind_1y+N*ind_2y+N*N*ind_3y];
      sb_tests62 = u_3[ind_1z+N*ind_2y+N*N*ind_3y];
      sb_tests72 = u_3[ind_1w+N*ind_2y+N*N*ind_3y];
      sb_tests82 = u_3[ind_1x+N*ind_2z+N*N*ind_3y];
      sb_tests92 = u_3[ind_1y+N*ind_2z+N*N*ind_3y];
      sb_testsa2 = u_3[ind_1z+N*ind_2z+N*N*ind_3y];
      sb_testsb2 = u_3[ind_1w+N*ind_2z+N*N*ind_3y];
      sb_testsc2 = u_3[ind_1x+N*ind_2w+N*N*ind_3y];
      sb_testsd2 = u_3[ind_1y+N*ind_2w+N*N*ind_3y];
      sb_testse2 = u_3[ind_1z+N*ind_2w+N*N*ind_3y];
      sb_testsf2 = u_3[ind_1w+N*ind_2w+N*N*ind_3y];

      sb_tests03 = u_3[ind_1x+N*ind_2x+N*N*ind_3z];
      sb_tests13 = u_3[ind_1y+N*ind_2x+N*N*ind_3z];
      sb_tests23 = u_3[ind_1z+N*ind_2x+N*N*ind_3z];
      sb_tests33 = u_3[ind_1w+N*ind_2x+N*N*ind_3z];
      sb_tests43 = u_3[ind_1x+N*ind_2y+N*N*ind_3z];
      sb_tests53 = u_3[ind_1y+N*ind_2y+N*N*ind_3z];
      sb_tests63 = u_3[ind_1z+N*ind_2y+N*N*ind_3z];
      sb_tests73 = u_3[ind_1w+N*ind_2y+N*N*ind_3z];
      sb_tests83 = u_3[ind_1x+N*ind_2z+N*N*ind_3z];
      sb_tests93 = u_3[ind_1y+N*ind_2z+N*N*ind_3z];
      sb_testsa3 = u_3[ind_1z+N*ind_2z+N*N*ind_3z];
      sb_testsb3 = u_3[ind_1w+N*ind_2z+N*N*ind_3z];
      sb_testsc3 = u_3[ind_1x+N*ind_2w+N*N*ind_3z];
      sb_testsd3 = u_3[ind_1y+N*ind_2w+N*N*ind_3z];
      sb_testse3 = u_3[ind_1z+N*ind_2w+N*N*ind_3z];
      sb_testsf3 = u_3[ind_1w+N*ind_2w+N*N*ind_3z];

      sb_tests04 = u_3[ind_1x+N*ind_2x+N*N*ind_3w];
      sb_tests14 = u_3[ind_1y+N*ind_2x+N*N*ind_3w];
      sb_tests24 = u_3[ind_1z+N*ind_2x+N*N*ind_3w];
      sb_tests34 = u_3[ind_1w+N*ind_2x+N*N*ind_3w];
      sb_tests44 = u_3[ind_1x+N*ind_2y+N*N*ind_3w];
      sb_tests54 = u_3[ind_1y+N*ind_2y+N*N*ind_3w];
      sb_tests64 = u_3[ind_1z+N*ind_2y+N*N*ind_3w];
      sb_tests74 = u_3[ind_1w+N*ind_2y+N*N*ind_3w];
      sb_tests84 = u_3[ind_1x+N*ind_2z+N*N*ind_3w];
      sb_tests94 = u_3[ind_1y+N*ind_2z+N*N*ind_3w];
      sb_testsa4 = u_3[ind_1z+N*ind_2z+N*N*ind_3w];
      sb_testsb4 = u_3[ind_1w+N*ind_2z+N*N*ind_3w];
      sb_testsc4 = u_3[ind_1x+N*ind_2w+N*N*ind_3w];
      sb_testsd4 = u_3[ind_1y+N*ind_2w+N*N*ind_3w];
      sb_testse4 = u_3[ind_1z+N*ind_2w+N*N*ind_3w];
      sb_testsf4 = u_3[ind_1w+N*ind_2w+N*N*ind_3w];

      q1 = sqrt(1.+4.0*r_1_c*(1-r_1_c)); 
      q2 = sqrt(1.+4.0*r_2_c*(1-r_2_c));
      q3 = sqrt(1.+4.0*r_3_stag*(1-r_3_stag));

      v1x = 3.-2.*r_1_c-q1; 
      v1y = 3.-2.*r_1_c+q1; 
      v1z = 1.+2.*r_1_c+q1; 
      v1w = 1.+2.*r_1_c-q1; 
      v1x = v1x/8.;
      v1y = v1y/8.;
      v1z = v1z/8.;
      v1w = v1w/8.;

      v2x = 3.-2.*r_2_c-q2; 
      v2y = 3.-2.*r_2_c+q2; 
      v2z = 1.+2.*r_2_c+q2; 
      v2w = 1.+2.*r_2_c-q2; 
      v2x = v2x/8.;
      v2y = v2y/8.;
      v2z = v2z/8.;
      v2w = v2w/8.;

      v3x = 3.-2.*r_3_stag-q3; 
      v3y = 3.-2.*r_3_stag+q3; 
      v3z = 1.+2.*r_3_stag+q3; 
      v3w = 1.+2.*r_3_stag-q3; 
      v3x = v3x/8.;
      v3y = v3y/8.;
      v3z = v3z/8.;
      v3w = v3w/8.;
      
      ws01 = v1x*v2x*v3x;
      ws11 = v1y*v2x*v3x;
      ws21 = v1z*v2x*v3x;
      ws31 = v1w*v2x*v3x;
      ws41 = v1x*v2y*v3x;
      ws51 = v1y*v2y*v3x;
      ws61 = v1z*v2y*v3x;
      ws71 = v1w*v2y*v3x;
      ws81 = v1x*v2z*v3x;
      ws91 = v1y*v2z*v3x;
      wsa1 = v1z*v2z*v3x;
      wsb1 = v1w*v2z*v3x;
      wsc1 = v1x*v2w*v3x;
      wsd1 = v1y*v2w*v3x;
      wse1 = v1z*v2w*v3x;
      wsf1 = v1w*v2w*v3x;
      
      ws02 = v1x*v2x*v3y;
      ws12 = v1y*v2x*v3y;
      ws22 = v1z*v2x*v3y;
      ws32 = v1w*v2x*v3y;
      ws42 = v1x*v2y*v3y;
      ws52 = v1y*v2y*v3y;
      ws62 = v1z*v2y*v3y;
      ws72 = v1w*v2y*v3y;
      ws82 = v1x*v2z*v3y;
      ws92 = v1y*v2z*v3y;
      wsa2 = v1z*v2z*v3y;
      wsb2 = v1w*v2z*v3y;
      wsc2 = v1x*v2w*v3y;
      wsd2 = v1y*v2w*v3y;
      wse2 = v1z*v2w*v3y;
      wsf2 = v1w*v2w*v3y;

      ws03 = v1x*v2x*v3z;
      ws13 = v1y*v2x*v3z;
      ws23 = v1z*v2x*v3z;
      ws33 = v1w*v2x*v3z;
      ws43 = v1x*v2y*v3z;
      ws53 = v1y*v2y*v3z;
      ws63 = v1z*v2y*v3z;
      ws73 = v1w*v2y*v3z;
      ws83 = v1x*v2z*v3z;
      ws93 = v1y*v2z*v3z;
      wsa3 = v1z*v2z*v3z;
      wsb3 = v1w*v2z*v3z;
      wsc3 = v1x*v2w*v3z;
      wsd3 = v1y*v2w*v3z;
      wse3 = v1z*v2w*v3z;
      wsf3 = v1w*v2w*v3z;

      ws04 = v1x*v2x*v3w;
      ws14 = v1y*v2x*v3w;
      ws24 = v1z*v2x*v3w;
      ws34 = v1w*v2x*v3w;
      ws44 = v1x*v2y*v3w;
      ws54 = v1y*v2y*v3w;
      ws64 = v1z*v2y*v3w;
      ws74 = v1w*v2y*v3w;
      ws84 = v1x*v2z*v3w;
      ws94 = v1y*v2z*v3w;
      wsa4 = v1z*v2z*v3w;
      wsb4 = v1w*v2z*v3w;
      wsc4 = v1x*v2w*v3w;
      wsd4 = v1y*v2w*v3w;
      wse4 = v1z*v2w*v3w;
      wsf4 = v1w*v2w*v3w;

      ws01 = ws01*sb_tests01;
      ws11 = ws11*sb_tests11;
      ws21 = ws21*sb_tests21;
      ws31 = ws31*sb_tests31;
      ws41 = ws41*sb_tests41;
      ws51 = ws51*sb_tests51;
      ws61 = ws61*sb_tests61;
      ws71 = ws71*sb_tests71;
      ws81 = ws81*sb_tests81;
      ws91 = ws91*sb_tests91;
      wsa1 = wsa1*sb_testsa1;
      wsb1 = wsb1*sb_testsb1;
      wsc1 = wsc1*sb_testsc1;
      wsd1 = wsd1*sb_testsd1;
      wse1 = wse1*sb_testse1;
      wsf1 = wsf1*sb_testsf1;

      ws02 = ws02*sb_tests02;
      ws12 = ws12*sb_tests12;
      ws22 = ws22*sb_tests22;
      ws32 = ws32*sb_tests32;
      ws42 = ws42*sb_tests42;
      ws52 = ws52*sb_tests52;
      ws62 = ws62*sb_tests62;
      ws72 = ws72*sb_tests72;
      ws82 = ws82*sb_tests82;
      ws92 = ws92*sb_tests92;
      wsa2 = wsa2*sb_testsa2;
      wsb2 = wsb2*sb_testsb2;
      wsc2 = wsc2*sb_testsc2;
      wsd2 = wsd2*sb_testsd2;
      wse2 = wse2*sb_testse2;
      wsf2 = wsf2*sb_testsf2;

      ws03 = ws03*sb_tests03;
      ws13 = ws13*sb_tests13;
      ws23 = ws23*sb_tests23;
      ws33 = ws33*sb_tests33;
      ws43 = ws43*sb_tests43;
      ws53 = ws53*sb_tests53;
      ws63 = ws63*sb_tests63;
      ws73 = ws73*sb_tests73;
      ws83 = ws83*sb_tests83;
      ws93 = ws93*sb_tests93;
      wsa3 = wsa3*sb_testsa3;
      wsb3 = wsb3*sb_testsb3;
      wsc3 = wsc3*sb_testsc3;
      wsd3 = wsd3*sb_testsd3;
      wse3 = wse3*sb_testse3;
      wsf3 = wsf3*sb_testsf3;

      ws04 = ws04*sb_tests04;
      ws14 = ws14*sb_tests14;
      ws24 = ws24*sb_tests24;
      ws34 = ws34*sb_tests34;
      ws44 = ws44*sb_tests44;
      ws54 = ws54*sb_tests54;
      ws64 = ws64*sb_tests64;
      ws74 = ws74*sb_tests74;
      ws84 = ws84*sb_tests84;
      ws94 = ws94*sb_tests94;
      wsa4 = wsa4*sb_testsa4;
      wsb4 = wsb4*sb_testsb4;
      wsc4 = wsc4*sb_testsc4;
      wsd4 = wsd4*sb_testsd4;
      wse4 = wse4*sb_testse4;
      wsf4 = wsf4*sb_testsf4;

      U_3[k] = ws01+ws11+ws21+ws31
	       +ws41+ws51+ws61+ws71
	       +ws81+ws91+wsa1+wsb1
	       +wsc1+wsd1+wse1+wsf1
               +ws02+ws12+ws22+ws32
	       +ws42+ws52+ws62+ws72
	       +ws82+ws92+wsa2+wsb2
	       +wsc2+wsd2+wse2+wsf2
               +ws03+ws13+ws23+ws33
	       +ws43+ws53+ws63+ws73
	       +ws83+ws93+wsa3+wsb3
	       +wsc3+wsd3+wse3+wsf3
               +ws04+ws14+ws24+ws34
	       +ws44+ws54+ws64+ws74
	       +ws84+ws94+wsa4+wsb4
	       +wsc4+wsd4+wse4+wsf4;
    }
    __kernel void spread_save(__global const int *firstn1, __global const int *nextn1, __global const int *firstn2, __global const int *nextn2, __global const float *F_1, __global const float *F_2, __global const float *X_1, __global const float *X_2, const unsigned N, const float dx, const float dtheta, const unsigned shift0, const unsigned shift1, __global float *f_1, __global float *f_2)
    {
      unsigned i = 4*get_global_id(0)+shift0;
      unsigned j = 4*get_global_id(1)+shift1;

      int k1 = firstn1[i+N*j]; 
      int k2 = firstn2[i+N*j]; 
      if (k1 == -1 && k2 == -1){
      return;
      }

      float c = dtheta/(dx*dx*dx);
      int ind_1x, ind_1y, ind_1z, ind_1w;
      int ind_2x, ind_2y, ind_2z, ind_2w;

      float f_10, f_11, f_12, f_13;
      float f_14, f_15, f_16, f_17;
      float f_18, f_19, f_1a, f_1b;
      float f_1c, f_1d, f_1e, f_1f;

      float f_20, f_21, f_22, f_23;
      float f_24, f_25, f_26, f_27;
      float f_28, f_29, f_2a, f_2b;
      float f_2c, f_2d, f_2e, f_2f;

      float v1x, v1y, v1z, v1w;
      float v2x, v2y, v2z, v2w;

      float q1, q2;

      float ws0, ws1, ws2, ws3;
      float ws4, ws5, ws6, ws7;
      float ws8, ws9, wsa, wsb;
      float wsc, wsd, wse, wsf;

      if (k1 !=-1){
      ind_1x = (i-1 & N-1);
      ind_1y = (i & N-1);
      ind_1z = (i+1 & N-1);
      ind_1w = (i+2 & N-1);

      ind_2x = (j-1 & N-1);
      ind_2y = (j & N-1);
      ind_2z = (j+1 & N-1);
      ind_2w = (j+2 & N-1);

      f_10=f_1[ind_1x+N*ind_2x];
      f_11=f_1[ind_1y+N*ind_2x];
      f_12=f_1[ind_1z+N*ind_2x];
      f_13=f_1[ind_1w+N*ind_2x];
      f_14=f_1[ind_1x+N*ind_2y];
      f_15=f_1[ind_1y+N*ind_2y];
      f_16=f_1[ind_1z+N*ind_2y];
      f_17=f_1[ind_1w+N*ind_2y];
      f_18=f_1[ind_1x+N*ind_2z];
      f_19=f_1[ind_1y+N*ind_2z];
      f_1a=f_1[ind_1z+N*ind_2z];
      f_1b=f_1[ind_1w+N*ind_2z];
      f_1c=f_1[ind_1x+N*ind_2w];
      f_1d=f_1[ind_1y+N*ind_2w];
      f_1e=f_1[ind_1z+N*ind_2w];
      f_1f=f_1[ind_1w+N*ind_2w];
      }

      while(k1 != -1)
      {
      float s_1_stag = (X_1[k1]+0.5)/dx;
      int i_1_stag = convert_int(floor(s_1_stag));
      float r_1_stag = s_1_stag-i_1_stag;
      float s_2_c = (X_2[k1]+0.5-dx/2)/dx;        
      int i_2_c = convert_int(floor(s_2_c));
      float r_2_c = s_2_c-i_2_c;
      
      q1 = sqrt(1.+4.0*r_1_stag*(1-r_1_stag)); 
      q2 = sqrt(1.+4.0*r_2_c*(1-r_2_c));

      v1x = 3.-2.*r_1_stag-q1; 
      v1y = 3.-2.*r_1_stag+q1; 
      v1z = 1.+2.*r_1_stag+q1; 
      v1w = 1.+2.*r_1_stag-q1; 
      v1x = v1x/8.;
      v1y = v1y/8.;
      v1z = v1z/8.;
      v1w = v1w/8.;

      v2x = 3.-2.*r_2_c-q2; 
      v2y = 3.-2.*r_2_c+q2; 
      v2z = 1.+2.*r_2_c+q2; 
      v2w = 1.+2.*r_2_c-q2; 
      v2x = v2x/8.;
      v2y = v2y/8.;
      v2z = v2z/8.;
      v2w = v2w/8.;
      
      ws0 = v1x*v2x;
      ws1 = v1y*v2x;
      ws2 = v1z*v2x;
      ws3 = v1w*v2x;
      ws4 = v1x*v2y;
      ws5 = v1y*v2y;
      ws6 = v1z*v2y;
      ws7 = v1w*v2y;
      ws8 = v1x*v2z;
      ws9 = v1y*v2z;
      wsa = v1z*v2z;
      wsb = v1w*v2z;
      wsc = v1x*v2w;
      wsd = v1y*v2w;
      wse = v1z*v2w;
      wsf = v1w*v2w;
      
      float my_F_1 = F_1[k1];
      f_10 += c*my_F_1*ws0;
      f_11 += c*my_F_1*ws1;
      f_12 += c*my_F_1*ws2;
      f_13 += c*my_F_1*ws3;
      f_14 += c*my_F_1*ws4;
      f_15 += c*my_F_1*ws5;
      f_16 += c*my_F_1*ws6;
      f_17 += c*my_F_1*ws7;
      f_18 += c*my_F_1*ws8;
      f_19 += c*my_F_1*ws9;
      f_1a += c*my_F_1*wsa;
      f_1b += c*my_F_1*wsb;
      f_1c += c*my_F_1*wsc;
      f_1d += c*my_F_1*wsd;
      f_1e += c*my_F_1*wse;
      f_1f += c*my_F_1*wsf;

      k1 = nextn1[k1];
      if (k1 == -1){
      f_1[ind_1x+N*ind_2x]=f_10;
      f_1[ind_1y+N*ind_2x]=f_11;
      f_1[ind_1z+N*ind_2x]=f_12;
      f_1[ind_1w+N*ind_2x]=f_13;
      f_1[ind_1x+N*ind_2y]=f_14;
      f_1[ind_1y+N*ind_2y]=f_15;
      f_1[ind_1z+N*ind_2y]=f_16;
      f_1[ind_1w+N*ind_2y]=f_17;
      f_1[ind_1x+N*ind_2z]=f_18;
      f_1[ind_1y+N*ind_2z]=f_19;
      f_1[ind_1z+N*ind_2z]=f_1a;
      f_1[ind_1w+N*ind_2z]=f_1b;
      f_1[ind_1x+N*ind_2w]=f_1c;
      f_1[ind_1y+N*ind_2w]=f_1d;
      f_1[ind_1z+N*ind_2w]=f_1e;
      f_1[ind_1w+N*ind_2w]=f_1f;
      }
      }

      if (k2 !=-1){
      ind_1x = (i-1 & N-1);
      ind_1y = (i & N-1);
      ind_1z = (i+1 & N-1);
      ind_1w = (i+2 & N-1);

      ind_2x = (j-1 & N-1);
      ind_2y = (j & N-1);
      ind_2z = (j+1 & N-1);
      ind_2w = (j+2 & N-1);

      f_20=f_2[ind_1x+N*ind_2x];
      f_21=f_2[ind_1y+N*ind_2x];
      f_22=f_2[ind_1z+N*ind_2x];
      f_23=f_2[ind_1w+N*ind_2x];
      f_24=f_2[ind_1x+N*ind_2y];
      f_25=f_2[ind_1y+N*ind_2y];
      f_26=f_2[ind_1z+N*ind_2y];
      f_27=f_2[ind_1w+N*ind_2y];
      f_28=f_2[ind_1x+N*ind_2z];
      f_29=f_2[ind_1y+N*ind_2z];
      f_2a=f_2[ind_1z+N*ind_2z];
      f_2b=f_2[ind_1w+N*ind_2z];
      f_2c=f_2[ind_1x+N*ind_2w];
      f_2d=f_2[ind_1y+N*ind_2w];
      f_2e=f_2[ind_1z+N*ind_2w];
      f_2f=f_2[ind_1w+N*ind_2w];
      }
      
      while (k2 != -1){
      float s_1_c = (X_1[k2]+0.5-dx/2)/dx;
      int i_1_c = convert_int(floor(s_1_c));
      float r_1_c = s_1_c-i_1_c;
      float s_2_stag = (X_2[k2]+0.5)/dx;        
      int i_2_stag = convert_int(floor(s_2_stag));
      float r_2_stag = s_2_stag-i_2_stag;

      q1 = sqrt(1.+4.0*r_1_c*(1-r_1_c)); 
      q2 = sqrt(1.+4.0*r_2_stag*(1-r_2_stag));

      v1x = 3.-2.*r_1_c-q1; 
      v1y = 3.-2.*r_1_c+q1; 
      v1z = 1.+2.*r_1_c+q1; 
      v1w = 1.+2.*r_1_c-q1; 
      v1x = v1x/8.;
      v1y = v1y/8.;
      v1z = v1z/8.;
      v1w = v1w/8.;

      v2x = 3.-2.*r_2_stag-q2; 
      v2y = 3.-2.*r_2_stag+q2; 
      v2z = 1.+2.*r_2_stag+q2; 
      v2w = 1.+2.*r_2_stag-q2; 
      v2x = v2x/8.;
      v2y = v2y/8.;
      v2z = v2z/8.;
      v2w = v2w/8.;
      
      ws0 = v1x*v2x;
      ws1 = v1y*v2x;
      ws2 = v1z*v2x;
      ws3 = v1w*v2x;
      ws4 = v1x*v2y;
      ws5 = v1y*v2y;
      ws6 = v1z*v2y;
      ws7 = v1w*v2y;
      ws8 = v1x*v2z;
      ws9 = v1y*v2z;
      wsa = v1z*v2z;
      wsb = v1w*v2z;
      wsc = v1x*v2w;
      wsd = v1y*v2w;
      wse = v1z*v2w;
      wsf = v1w*v2w;
      
      float my_F_2 = F_2[k2];
      f_20 += c*my_F_2*ws0;
      f_21 += c*my_F_2*ws1;
      f_22 += c*my_F_2*ws2;
      f_23 += c*my_F_2*ws3;
      f_24 += c*my_F_2*ws4;
      f_25 += c*my_F_2*ws5;
      f_26 += c*my_F_2*ws6;
      f_27 += c*my_F_2*ws7;
      f_28 += c*my_F_2*ws8;
      f_29 += c*my_F_2*ws9;
      f_2a += c*my_F_2*wsa;
      f_2b += c*my_F_2*wsb;
      f_2c += c*my_F_2*wsc;
      f_2d += c*my_F_2*wsd;
      f_2e += c*my_F_2*wse;
      f_2f += c*my_F_2*wsf;

      k2 = nextn2[k2];
      if (k2 == -1){
      f_2[ind_1x+N*ind_2x]=f_20;
      f_2[ind_1y+N*ind_2x]=f_21;
      f_2[ind_1z+N*ind_2x]=f_22;
      f_2[ind_1w+N*ind_2x]=f_23;
      f_2[ind_1x+N*ind_2y]=f_24;
      f_2[ind_1y+N*ind_2y]=f_25;
      f_2[ind_1z+N*ind_2y]=f_26;
      f_2[ind_1w+N*ind_2y]=f_27;
      f_2[ind_1x+N*ind_2z]=f_28;
      f_2[ind_1y+N*ind_2z]=f_29;
      f_2[ind_1z+N*ind_2z]=f_2a;
      f_2[ind_1w+N*ind_2z]=f_2b;
      f_2[ind_1x+N*ind_2w]=f_2c;
      f_2[ind_1y+N*ind_2w]=f_2d;
      f_2[ind_1z+N*ind_2w]=f_2e;
      f_2[ind_1w+N*ind_2w]=f_2f;
      }
      }
    }
    __kernel void updaten(__global int *firstn1, __global int *nextn1, __global int *firstn2, __global int *nextn2, __global int *firstn3, __global int *nextn3, __global const float *X_1, __global const float *X_2, __global const float *X_3, const unsigned N, const float dx, const unsigned shift0, const unsigned shift1, const unsigned shift2)
    {
      unsigned i = 4*get_global_id(0)+shift0;
      unsigned j = 4*get_global_id(1)+shift1;
      unsigned k = 4*get_global_id(2)+shift2;

      int k1 = firstn1[i+N*j+N*N*k]; 
      int k2 = firstn2[i+N*j+N*N*k]; 
      int k3 = firstn3[i+N*j+N*N*k]; 

      if (k1 == -1 && k2 == -1 && k3 == -1){
      return;
      }

      uint ind_1, ind_2, ind_3;
      int nextnold;

      int nprev1 = -1;
      while(k1 != -1)
      {
      float s_1_stag = (X_1[k1]+0.5)/dx;
      int i_1_stag = convert_int(floor(s_1_stag));
      float s_2_c = (X_2[k1]+0.5-dx/2)/dx;        
      int i_2_c = convert_int(floor(s_2_c));
      float s_3_c = (X_3[k1]+0.5-dx/2)/dx;        
      int i_3_c = convert_int(floor(s_3_c));
      
      ind_1 = (i_1_stag & N-1);
      ind_2 = (i_2_c & N-1);
      ind_3 = (i_3_c & N-1);

      if (ind_1 == i && ind_2 == j && ind_3 == k){
      nprev1 = k1;
      k1 = nextn1[k1];
      }
      else {
      nextnold = nextn1[k1];
      nextn1[k1] = firstn1[ind_1+N*ind_2+N*N*ind_3];
      firstn1[ind_1+N*ind_2+N*N*ind_3] = k1;
      k1 = nextnold;
          if (nprev1 == -1) {
          firstn1[i+N*j+N*N*k] = nextnold;
          }
          else {
          nextn1[nprev1] = nextnold;
          }
      }
      }

      int nprev2 = -1;
      while(k2 != -1)
      {
      float s_1_c = (X_1[k2]+0.5-dx/2)/dx;
      int i_1_c = convert_int(floor(s_1_c));
      float s_2_stag = (X_2[k2]+0.5)/dx;        
      int i_2_stag = convert_int(floor(s_2_stag));
      float s_3_c = (X_3[k2]+0.5-dx/2)/dx;
      int i_3_c = convert_int(floor(s_3_c));
      
      ind_1 = (i_1_c & N-1);
      ind_2 = (i_2_stag & N-1);
      ind_3 = (i_3_c & N-1);

      if (ind_1 == i && ind_2 == j && ind_3 == k){
      nprev2 = k2;
      k2 = nextn2[k2];
      }
      else {
      nextnold = nextn2[k2];
      nextn2[k2] = firstn2[ind_1+N*ind_2+N*N*ind_3];
      firstn2[ind_1+N*ind_2+N*N*ind_3] = k2;
      k2 = nextnold;
          if (nprev2 == -1) {
          firstn2[i+N*j+N*N*k] = nextnold;
          }
          else {
          nextn2[nprev2] = nextnold;
          }
      }
      }

      int nprev3 = -1;
      while(k3 != -1)
      {
      float s_1_c = (X_1[k3]+0.5-dx/2)/dx;
      int i_1_c = convert_int(floor(s_1_c));
      float s_2_c = (X_2[k3]+0.5-dx/2)/dx;        
      int i_2_c = convert_int(floor(s_2_c));
      float s_3_stag = (X_3[k3]+0.5)/dx;
      int i_3_stag = convert_int(floor(s_3_stag));
      
      ind_1 = (i_1_c & N-1);
      ind_2 = (i_2_c & N-1);
      ind_3 = (i_3_stag & N-1);

      if (ind_1 == i && ind_2 == j && ind_3 == k){
      nprev3 = k3;
      k3 = nextn3[k3];
      }
      else {
      nextnold = nextn3[k3];
      nextn3[k3] = firstn3[ind_1+N*ind_2+N*N*ind_3];
      firstn3[ind_1+N*ind_2+N*N*ind_3] = k3;
      k3 = nextnold;
          if (nprev3 == -1) {
          firstn3[i+N*j+N*N*k] = nextnold;
          }
          else {
          nextn3[nprev3] = nextnold;
          }
      }
    }
    }
    __kernel void calc_lagF_teth(__global const float *X_1, __global const float *X_2, __global const float *X_3, __global const float *X_1_teth, __global const float *X_2_teth, __global const float *X_3_teth, __global const unsigned *i_teth, const float k_teth, const float dr, __global float *F_1, __global float *F_2, __global float *F_3)
    { 
    unsigned i = get_global_id(0);

    F_1[i] = -k_teth/dr*(X_1[i_teth[i]]-X_1_teth[i]); 
    F_2[i] = -k_teth/dr*(X_2[i_teth[i]]-X_2_teth[i]); 
    F_3[i] = -k_teth/dr*(X_3[i_teth[i]]-X_3_teth[i]); 
    }
    __kernel void calc_lagF_area(__global const float *X_1, __global const float *X_2, __global const float *X_3, __global const unsigned *TV_1, __global const unsigned *TV_2, __global const unsigned *TV_3, __global const float *A_0, __global const int *CT, const unsigned CT_max, const float k_area, __global float *F_1, __global float *F_2, __global float *F_3)
    { 
    unsigned i = get_global_id(0);

    float X_11, X_12, X_13;
    float X_21, X_22, X_23;
    float X_31, X_32, X_33;

    float n1, n2, n3, norm;
    float a1, a2, a3;
    float b1, b2, b3;

    unsigned j = 0;
    unsigned k;

    while (j < CT_max && CT[j+CT_max*i] != -1) { 
    k = CT[j+CT_max*i];

    if (TV_1[k] == i) {
    X_11 = X_1[TV_1[k]];
    X_12 = X_2[TV_1[k]];
    X_13 = X_3[TV_1[k]];

    X_21 = X_1[TV_2[k]];
    X_22 = X_2[TV_2[k]];
    X_23 = X_3[TV_2[k]];

    X_31 = X_1[TV_3[k]];
    X_32 = X_2[TV_3[k]];
    X_33 = X_3[TV_3[k]];
    }
    else if (TV_2[k] == i) {
    X_11 = X_1[TV_2[k]];
    X_12 = X_2[TV_2[k]];
    X_13 = X_3[TV_2[k]];

    X_21 = X_1[TV_3[k]];
    X_22 = X_2[TV_3[k]];
    X_23 = X_3[TV_3[k]];

    X_31 = X_1[TV_1[k]];
    X_32 = X_2[TV_1[k]];
    X_33 = X_3[TV_1[k]];
    }
    else {
    X_11 = X_1[TV_3[k]];
    X_12 = X_2[TV_3[k]];
    X_13 = X_3[TV_3[k]];

    X_21 = X_1[TV_1[k]];
    X_22 = X_2[TV_1[k]];
    X_23 = X_3[TV_1[k]];

    X_31 = X_1[TV_2[k]];
    X_32 = X_2[TV_2[k]];
    X_33 = X_3[TV_2[k]];
    }

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    norm = sqrt(n1*n1+n2*n2+n3*n3);
    n1 = n1/norm;
    n2 = n2/norm;
    n3 = n3/norm;

    a1 = X_21-X_31;
    a2 = X_22-X_32;
    a3 = X_23-X_33;

    b1 = 0.5*(n2*a3-n3*a2);
    b2 = 0.5*(n3*a1-n1*a3);
    b3 = 0.5*(n1*a2-n2*a1);

    //F_1[i] += k_area*(0.5*norm-A_0[k])*b1; 
    //F_2[i] += k_area*(0.5*norm-A_0[k])*b2; 
    //F_3[i] += k_area*(0.5*norm-A_0[k])*b3; 
    F_1[i] += k_area*(1.0-0.5*norm/A_0[k])*b1*(-1.0)/A_0[k]; 
    F_2[i] += k_area*(1.0-0.5*norm/A_0[k])*b2*(-1.0)/A_0[k]; 
    F_3[i] += k_area*(1.0-0.5*norm/A_0[k])*b3*(-1.0)/A_0[k]; 

    j = j+1;
    }
    }
    __kernel void calc_lagF_area_old(__global const float *X_1, __global const float *X_2, __global const float *X_3, __global const unsigned *TV_1, __global const unsigned *TV_2, __global const unsigned *TV_3, __global const float *A_0, const float k_area, const unsigned N_tri, __global float *F_1, __global float *F_2, __global float *F_3)
    { 
    unsigned i = get_global_id(0);

    float X_11, X_12, X_13;
    float X_21, X_22, X_23;
    float X_31, X_32, X_33;

    float n1, n2, n3, norm;
    float a1, a2, a3;
    float b1, b2, b3;

    //for (unsigned i=0; i<N_tri; i++) {
    X_11 = X_1[TV_1[i]];
    X_12 = X_2[TV_1[i]];
    X_13 = X_3[TV_1[i]];

    X_21 = X_1[TV_2[i]];
    X_22 = X_2[TV_2[i]];
    X_23 = X_3[TV_2[i]];

    X_31 = X_1[TV_3[i]];
    X_32 = X_2[TV_3[i]];
    X_33 = X_3[TV_3[i]];

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    norm = sqrt(n1*n1+n2*n2+n3*n3);
    n1 = n1/norm;
    n2 = n2/norm;
    n3 = n3/norm;

    a1 = X_31-X_21;
    a2 = X_32-X_22;
    a3 = X_33-X_23;

    b1 = 0.5*(n2*a3-n3*a2);
    b2 = 0.5*(n3*a1-n1*a3);
    b3 = 0.5*(n1*a2-n2*a1);

    F_1[TV_1[i]] += (0.5*norm-A_0[i])*b1; 
    F_2[TV_1[i]] += (0.5*norm-A_0[i])*b2; 
    F_3[TV_1[i]] += (0.5*norm-A_0[i])*b3; 

    a1 = X_11-X_31;
    a2 = X_12-X_32;
    a3 = X_13-X_33;

    b1 = 0.5*(n2*a3-n3*a2);
    b2 = 0.5*(n3*a1-n1*a3);
    b3 = 0.5*(n1*a2-n2*a1);

    F_1[TV_2[i]] += (0.5*norm-A_0[i])*b1; 
    F_2[TV_2[i]] += (0.5*norm-A_0[i])*b2; 
    F_3[TV_2[i]] += (0.5*norm-A_0[i])*b3; 

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = 0.5*(n2*a3-n3*a2);
    b2 = 0.5*(n3*a1-n1*a3);
    b3 = 0.5*(n1*a2-n2*a1);

    F_1[TV_3[i]] += (0.5*norm-A_0[i])*b1; 
    F_2[TV_3[i]] += (0.5*norm-A_0[i])*b2; 
    F_3[TV_3[i]] += (0.5*norm-A_0[i])*b3; 
    //}
    }
    __kernel void calc_lagF_test(__global const float *X_1, __global const float *X_2, __global const float *X_3, __global float *F_1, __global float *F_2, __global float *F_3)
    { 
    F_1[0] += X_1[0]; 
    }
    __kernel void calc_energy_test(__global const float *X_1, __global const float *X_2, __global const float *X_3, __global float *en)
    { 
    en[0] += 0.5*X_1[0]*X_1[0];
    }
    __kernel void calc_energy_area(__global const float *X_1, __global const float *X_2, __global const float *X_3, __global const unsigned *TV_1, __global const unsigned *TV_2, __global const unsigned *TV_3, __global const float *A_0, const float k_area, const unsigned N_tri, __global float *en)
    { 
    //unsigned i = get_global_id(0);

    float X_11, X_12, X_13;
    float X_21, X_22, X_23;
    float X_31, X_32, X_33;

    float n1, n2, n3, norm;
    float a1, a2, a3;
    float b1, b2, b3;

    for (unsigned i=0; i<N_tri; i++) {
    X_11 = X_1[TV_1[i]];
    X_12 = X_2[TV_1[i]];
    X_13 = X_3[TV_1[i]];

    X_21 = X_1[TV_2[i]];
    X_22 = X_2[TV_2[i]];
    X_23 = X_3[TV_2[i]];

    X_31 = X_1[TV_3[i]];
    X_32 = X_2[TV_3[i]];
    X_33 = X_3[TV_3[i]];

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    norm = sqrt(n1*n1+n2*n2+n3*n3);

    //en[0] += 0.5*k_area*(0.5*norm-A_0[i])*(0.5*norm-A_0[i]);
    en[0] += 0.5*k_area*(1.0-0.5*norm/A_0[i])*(1.0-0.5*norm/A_0[i]);
    }
    }
    __kernel void calc_lagF_hook(__global const float *X_1, __global const float *X_2, __global const float *X_3, __global const unsigned *TV_1, __global const unsigned *TV_2, __global const unsigned *TV_3, __global const float *X_ref_1, __global const float *X_ref_2, __global const float *X_ref_3, __global const float *A_0, __global const int *CT, const unsigned CT_max, const float k_bulk, const float k_shear, __global float *F_1, __global float *F_2, __global float *F_3)
    { 
    unsigned i = get_global_id(0);

    float X_11, X_12, X_13;
    float X_21, X_22, X_23;
    float X_31, X_32, X_33;

    float n1, n2, n3, norm, area, fac;
    float a1, a2, a3;
    float b1, b2, b3;
    float c1, c2, c3;
    float d1, d2, d3;
    float e1, e2, e3;
    float da1, da2, da3;

    float Z_11, Z_12, Z_13;
    float Z_21, Z_22, Z_23;
    float Z_31, Z_32, Z_33;

    unsigned j = 0;
    unsigned k;

    while (j < CT_max && CT[j+CT_max*i] != -1) { 
    k = CT[j+CT_max*i];

    if (TV_1[k] == i) {
    X_11 = X_ref_1[TV_1[k]];
    X_12 = X_ref_2[TV_1[k]];
    X_13 = X_ref_3[TV_1[k]];

    X_21 = X_ref_1[TV_2[k]];
    X_22 = X_ref_2[TV_2[k]];
    X_23 = X_ref_3[TV_2[k]];

    X_31 = X_ref_1[TV_3[k]];
    X_32 = X_ref_2[TV_3[k]];
    X_33 = X_ref_3[TV_3[k]];
    }
    else if (TV_2[k] == i) {
    X_11 = X_ref_1[TV_2[k]];
    X_12 = X_ref_2[TV_2[k]];
    X_13 = X_ref_3[TV_2[k]];

    X_21 = X_ref_1[TV_3[k]];
    X_22 = X_ref_2[TV_3[k]];
    X_23 = X_ref_3[TV_3[k]];

    X_31 = X_ref_1[TV_1[k]];
    X_32 = X_ref_2[TV_1[k]];
    X_33 = X_ref_3[TV_1[k]];
    }
    else {
    X_11 = X_ref_1[TV_3[k]];
    X_12 = X_ref_2[TV_3[k]];
    X_13 = X_ref_3[TV_3[k]];

    X_21 = X_ref_1[TV_1[k]];
    X_22 = X_ref_2[TV_1[k]];
    X_23 = X_ref_3[TV_1[k]];

    X_31 = X_ref_1[TV_2[k]];
    X_32 = X_ref_2[TV_2[k]];
    X_33 = X_ref_3[TV_2[k]];
    }

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    c1 = X_21-X_31;
    c2 = X_22-X_32;
    c3 = X_23-X_33;

    d1 = -b1;
    d2 = -b2;
    d3 = -b3;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    norm = sqrt(n1*n1+n2*n2+n3*n3);
    area = 0.5*norm;

    if (TV_1[k] == i) {
    X_11 = X_1[TV_1[k]];
    X_12 = X_2[TV_1[k]];
    X_13 = X_3[TV_1[k]];

    X_21 = X_1[TV_2[k]];
    X_22 = X_2[TV_2[k]];
    X_23 = X_3[TV_2[k]];

    X_31 = X_1[TV_3[k]];
    X_32 = X_2[TV_3[k]];
    X_33 = X_3[TV_3[k]];
    }
    else if (TV_2[k] == i) {
    X_11 = X_1[TV_2[k]];
    X_12 = X_2[TV_2[k]];
    X_13 = X_3[TV_2[k]];

    X_21 = X_1[TV_3[k]];
    X_22 = X_2[TV_3[k]];
    X_23 = X_3[TV_3[k]];

    X_31 = X_1[TV_1[k]];
    X_32 = X_2[TV_1[k]];
    X_33 = X_3[TV_1[k]];
    }
    else {
    X_11 = X_1[TV_3[k]];
    X_12 = X_2[TV_3[k]];
    X_13 = X_3[TV_3[k]];

    X_21 = X_1[TV_1[k]];
    X_22 = X_2[TV_1[k]];
    X_23 = X_3[TV_1[k]];

    X_31 = X_1[TV_2[k]];
    X_32 = X_2[TV_2[k]];
    X_33 = X_3[TV_2[k]];
    }

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    e1 = X_21-X_31;
    e2 = X_22-X_32;
    e3 = X_23-X_33;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    norm = sqrt(n1*n1+n2*n2+n3*n3);

    da1 = 0.5/norm*((e1*e1+e2*e2+e3*e3)*-b1+(e1*b1+e2*b2+e3*b3)*e1); 
    da2 = 0.5/norm*((e1*e1+e2*e2+e3*e3)*-b2+(e1*b1+e2*b2+e3*b3)*e2); 
    da3 = 0.5/norm*((e1*e1+e2*e2+e3*e3)*-b3+(e1*b1+e2*b2+e3*b3)*e3); 
    fac = (b1*b1+b2*b2+b3*b3)*(c1*c1+c2*c2+c3*c3)+2.0*(c1*d1+c2*d2+c3*d3)*(b1*e1+b2*e2+b3*e3)+(e1*e1+e2*e2+e3*e3)*(d1*d1+d2*d2+d3*d3);

    F_1[i] += -k_bulk*(0.5*norm/area-1.0)*da1;
    F_2[i] += -k_bulk*(0.5*norm/area-1.0)*da2;
    F_3[i] += -k_bulk*(0.5*norm/area-1.0)*da3;
    //F_1[i] += k_shear*(0.5*fac/(norm*norm)*da1-0.5/norm*((c1*c1+c2*c2+c3*c3)*-b1-(c1*d1+c2*d2+c3*d3)*e1));
    //F_2[i] += k_shear*(0.5*fac/(norm*norm)*da2-0.5/norm*((c1*c1+c2*c2+c3*c3)*-b2-(c1*d1+c2*d2+c3*d3)*e2));
    //F_3[i] += k_shear*(0.5*fac/(norm*norm)*da3-0.5/norm*((c1*c1+c2*c2+c3*c3)*-b3-(c1*d1+c2*d2+c3*d3)*e3));

    j = j+1;
    }
    }
    __kernel void calc_energy_hook(__global const float *X_1, __global const float *X_2, __global const float *X_3, __global const unsigned *TV_1, __global const unsigned *TV_2, __global const unsigned *TV_3, __global const float *X_ref_1, __global const float *X_ref_2, __global const float *X_ref_3, __global const float *A_0, const float k_bulk, const float k_shear, const unsigned N_tri, __global float *en)
    { 
    //unsigned i = get_global_id(0);

    float X_11, X_12, X_13;
    float X_21, X_22, X_23;
    float X_31, X_32, X_33;

    float Z_11, Z_12, Z_13;
    float Z_21, Z_22, Z_23;
    float Z_31, Z_32, Z_33;

    float n1, n2, n3, norm, area, theta;
    float a1, a2, a3;
    float b1, b2, b3;
    float c1, c2, c3;
    float d1, d2, d3;
    float e1, e2, e3;

    for (unsigned i=0; i<N_tri; i++) {
    X_11 = X_ref_1[TV_1[i]];
    X_12 = X_ref_2[TV_1[i]];
    X_13 = X_ref_3[TV_1[i]];

    X_21 = X_ref_1[TV_2[i]];
    X_22 = X_ref_2[TV_2[i]];
    X_23 = X_ref_3[TV_2[i]];

    X_31 = X_ref_1[TV_3[i]];
    X_32 = X_ref_2[TV_3[i]];
    X_33 = X_ref_3[TV_3[i]];

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;
   
    c1 = X_21-X_31;
    c2 = X_22-X_32;
    c3 = X_23-X_33;

    d1 = -b1;
    d2 = -b2;
    d3 = -b3;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    norm = sqrt(n1*n1+n2*n2+n3*n3);
    area = 0.5*norm;

    X_11 = X_1[TV_1[i]];
    X_12 = X_2[TV_1[i]];
    X_13 = X_3[TV_1[i]];

    X_21 = X_1[TV_2[i]];
    X_22 = X_2[TV_2[i]];
    X_23 = X_3[TV_2[i]];

    X_31 = X_1[TV_3[i]];
    X_32 = X_2[TV_3[i]];
    X_33 = X_3[TV_3[i]];

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    e1 = X_21-X_31;
    e2 = X_22-X_32;
    e3 = X_23-X_33;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    norm = sqrt(n1*n1+n2*n2+n3*n3);

    en[0] += 0.5*k_bulk*(0.5*norm/area-1.0)*(0.5*norm/area-1.0)*area;
    //en[0] += 0.5*k_shear*(((b1*b1+b2*b2+b3*b3)*(c1*c1+c2*c2+c3*c3)+2.0*(c1*d1+c2*d2+c3*d3)*(b1*e1+b2*e2+b3*e3)+(e1*e1+e2*e2+e3*e3)*(d1*d1+d2*d2+d3*d3))*0.5/norm-2.0*area);
    }
    }
    __kernel void calc_F_curv(__global const float *X_1, __global const float *X_2, __global const float *X_3, __global const unsigned *TV_1, __global const unsigned *TV_2, __global const unsigned *TV_3, __global const int *CT, const unsigned CT_max, const unsigned N_r, const float k_curv, __global float *F_1, __global float *F_2, __global float *F_3)
    { 
    unsigned i = N_r + get_global_id(0);
    //i = 0;

    float X_11, X_12, X_13;
    float X_21, X_22, X_23;
    float X_31, X_32, X_33;

    float n1, n2, n3, norm;
    float a1, a2, a3;
    float b1, b2, b3;
    float c1, c2, c3;
    float l1, l2, l3;
    float m1, m2, m3;

    float H1, H2, H3;
    float A1, A2, A3;
    float area;

    A1 = 0;
    A2 = 0;
    A3 = 0;

    H1 = 0;
    H2 = 0;
    H3 = 0;

    area = 0;

    float dH_11=0.0, dH_12=0.0, dH_13=0.0;
    float dH_21=0.0, dH_22=0.0, dH_23=0.0;
    float dH_31=0.0, dH_32=0.0, dH_33=0.0;

    float dH_11_v2=0.0, dH_12_v2=0.0, dH_13_v2=0.0;
    float dH_21_v2=0.0, dH_22_v2=0.0, dH_23_v2=0.0;
    float dH_31_v2=0.0, dH_32_v2=0.0, dH_33_v2=0.0;

    float dH_11_v3=0.0, dH_12_v3=0.0, dH_13_v3=0.0;
    float dH_21_v3=0.0, dH_22_v3=0.0, dH_23_v3=0.0;
    float dH_31_v3=0.0, dH_32_v3=0.0, dH_33_v3=0.0;

    float dA_11=0.0, dA_12=0.0, dA_13=0.0;
    float dA_21=0.0, dA_22=0.0, dA_23=0.0;
    float dA_31=0.0, dA_32=0.0, dA_33=0.0;

    unsigned k, v2, v3, l, m, v2o, v3o;
    unsigned j = 0;

    //first, calculate grad of i^th term of sum
    while (j < CT_max && CT[j+CT_max*i] != -1) { 
    k = CT[j+CT_max*i];

    if (TV_1[k] == i) {
    X_11 = X_1[TV_1[k]];
    X_12 = X_2[TV_1[k]];
    X_13 = X_3[TV_1[k]];

    X_21 = X_1[TV_2[k]];
    X_22 = X_2[TV_2[k]];
    X_23 = X_3[TV_2[k]];

    X_31 = X_1[TV_3[k]];
    X_32 = X_2[TV_3[k]];
    X_33 = X_3[TV_3[k]];

    v2 = TV_2[k];
    v3 = TV_3[k];
    }
    else if (TV_2[k] == i) {
    X_11 = X_1[TV_2[k]];
    X_12 = X_2[TV_2[k]];
    X_13 = X_3[TV_2[k]];

    X_21 = X_1[TV_3[k]];
    X_22 = X_2[TV_3[k]];
    X_23 = X_3[TV_3[k]];

    X_31 = X_1[TV_1[k]];
    X_32 = X_2[TV_1[k]];
    X_33 = X_3[TV_1[k]];

    v2 = TV_3[k];
    v3 = TV_1[k];
    }
    else {
    X_11 = X_1[TV_3[k]];
    X_12 = X_2[TV_3[k]];
    X_13 = X_3[TV_3[k]];

    X_21 = X_1[TV_1[k]];
    X_22 = X_2[TV_1[k]];
    X_23 = X_3[TV_1[k]];

    X_31 = X_1[TV_2[k]];
    X_32 = X_2[TV_2[k]];
    X_33 = X_3[TV_2[k]];

    v2 = TV_1[k];
    v3 = TV_2[k];
    }

    //compute derivatives of unit normal

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    A1 += 0.5*n1;
    A2 += 0.5*n2;
    A3 += 0.5*n3;

    norm = sqrt(n1*n1+n2*n2+n3*n3);

    area += 1.0/6.0*norm;

    n1 = n1/norm;
    n2 = n2/norm;
    n3 = n3/norm;

    a1 = X_21-X_31;
    a2 = X_22-X_32;
    a3 = X_23-X_33;

    b1 = n2*a3-n3*a2;
    b2 = n3*a1-n1*a3;
    b3 = n1*a2-n2*a1;

    H1 += 0.5*b1; 
    H2 += 0.5*b2; 
    H3 += 0.5*b3; 

    a1 = X_31-X_21;
    a2 = X_32-X_22;
    a3 = X_33-X_23;

    b1 = 1.0;
    b2 = 0.0;
    b3 = 0.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    dH_11 += 0.5*m1;
    dH_21 += 0.5*m2;
    dH_31 += 0.5*m3;

    b1 = 0.0;
    b2 = 1.0;
    b3 = 0.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    dH_12 += 0.5*m1;
    dH_22 += 0.5*m2;
    dH_32 += 0.5*m3;

    b1 = 0.0;
    b2 = 0.0;
    b3 = 1.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    dH_13 += 0.5*m1;
    dH_23 += 0.5*m2;
    dH_33 += 0.5*m3;

    a1 = X_11-X_31;
    a2 = X_12-X_32;
    a3 = X_13-X_33;

    b1 = 1.0;
    b2 = 0.0;
    b3 = 0.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    c1 = 1.0;
    c2 = 0.0;
    c3 = 0.0;

    l1 = n2*c3-n3*c2;
    l2 = n3*c1-n1*c3;
    l3 = n1*c2-n2*c1;

    dH_11_v2 += 0.5*(m1+l1);
    dH_21_v2 += 0.5*(m2+l2);
    dH_31_v2 += 0.5*(m3+l3);

    b1 = 0.0;
    b2 = 1.0;
    b3 = 0.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    c1 = 0.0;
    c2 = 1.0;
    c3 = 0.0;

    l1 = n2*c3-n3*c2;
    l2 = n3*c1-n1*c3;
    l3 = n1*c2-n2*c1;

    dH_12_v2 += 0.5*(m1+l1);
    dH_22_v2 += 0.5*(m2+l2);
    dH_32_v2 += 0.5*(m3+l3);

    b1 = 0.0;
    b2 = 0.0;
    b3 = 1.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    c1 = 0.0;
    c2 = 0.0;
    c3 = 1.0;

    l1 = n2*c3-n3*c2;
    l2 = n3*c1-n1*c3;
    l3 = n1*c2-n2*c1;

    dH_13_v2 += 0.5*(m1+l1);
    dH_23_v2 += 0.5*(m2+l2);
    dH_33_v2 += 0.5*(m3+l3);

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = 1.0;
    b2 = 0.0;
    b3 = 0.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    c1 = -1.0;
    c2 = 0.0;
    c3 = 0.0;

    l1 = n2*c3-n3*c2;
    l2 = n3*c1-n1*c3;
    l3 = n1*c2-n2*c1;

    dH_11_v3 += 0.5*(m1+l1);
    dH_21_v3 += 0.5*(m2+l2);
    dH_31_v3 += 0.5*(m3+l3);

    b1 = 0.0;
    b2 = 1.0;
    b3 = 0.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    c1 = 0.0;
    c2 = -1.0;
    c3 = 0.0;

    l1 = n2*c3-n3*c2;
    l2 = n3*c1-n1*c3;
    l3 = n1*c2-n2*c1;

    dH_12_v3 += 0.5*(m1+l1);
    dH_22_v3 += 0.5*(m2+l2);
    dH_32_v3 += 0.5*(m3+l3);

    b1 = 0.0;
    b2 = 0.0;
    b3 = 1.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    c1 = 0.0;
    c2 = 0.0;
    c3 = -1.0;

    l1 = n2*c3-n3*c2;
    l2 = n3*c1-n1*c3;
    l3 = n1*c2-n2*c1;

    dH_13_v3 += 0.5*(m1+l1);
    dH_23_v3 += 0.5*(m2+l2);
    dH_33_v3 += 0.5*(m3+l3);

    a1 = 1.0;
    a2 = 0.0;
    a3 = 0.0;

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    dA_11 += 0.5*m1; 
    dA_21 += 0.5*m2; 
    dA_31 += 0.5*m3; 

    a1 = 0.0;
    a2 = 1.0;
    a3 = 0.0;

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    dA_12 += 0.5*m1; 
    dA_22 += 0.5*m2; 
    dA_32 += 0.5*m3; 

    a1 = 0.0;
    a2 = 0.0;
    a3 = 1.0;

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    dA_13 += 0.5*m1; 
    dA_23 += 0.5*m2; 
    dA_33 += 0.5*m3; 

    j += 1;
    }

    m1 = H1*dH_11+H2*dH_21+H3*dH_31;
    m2 = A1*A1+A2*A2+A3*A3;
    m3 = H1*H1+H2*H2+H3*H3;
    c1 = A1*dA_11+A2*dA_21+A3*dA_31;
    F_1[i] -= k_curv*(2.0*area*(m1*m2-m3*c1)/(m2*m2)-1.0/3.0*H1*m3/m2);
    //F_1[i] += 2.0*(m1*m2-m3*c1)/(m2*m2);
    //F_1[i] += 2.0*m1;
    //F_1[i] += 2.0*H2*dH_21;
    //F_1[i] += dH_21;

    m1 = H1*dH_12+H2*dH_22+H3*dH_32;
    c1 = A1*dA_12+A2*dA_22+A3*dA_32;
    F_2[i] -= k_curv*(2.0*area*(m1*m2-m3*c1)/(m2*m2)-1.0/3.0*H2*m3/m2);
    //F_2[i] += 2.0*(m1*m2-m3*c1)/(m2*m2);
    //F_2[i] += 2.0*m1;
    //F_2[i] += 2.0*H2*dH_22;
    //F_2[i] += dH_22;

    m1 = H1*dH_13+H2*dH_23+H3*dH_33;
    c1 = A1*dA_13+A2*dA_23+A3*dA_33;
    F_3[i] -= k_curv*(2.0*area*(m1*m2-m3*c1)/(m2*m2)-1.0/3.0*H3*m3/m2);
    //F_3[i] += 2.0*(m1*m2-m3*c1)/(m2*m2);
    //F_3[i] += 2.0*m1;
    //F_3[i] += 2.0*H2*dH_23;
    //F_3[i] += dH_23;

    j = 0;
    //next, calculate grad of v2^th, v3^th terms of sum with triangles touching i
    while (j < CT_max && CT[j+CT_max*i] != -1) { 
    k = CT[j+CT_max*i];

    if (TV_1[k] == i) {
    v2o = TV_2[k];
    v3o = TV_3[k];
    }
    else if (TV_2[k] == i) {
    v2o = TV_3[k];
    v3o = TV_1[k];
    }
    else {
    v2o = TV_1[k];
    v3o = TV_2[k];
    }

    A1 = 0;
    A2 = 0;
    A3 = 0;

    H1 = 0;
    H2 = 0;
    H3 = 0;

    area = 0;

    l = 0;
    while (l < CT_max && CT[l+CT_max*v2o] != -1) { 
    m = CT[l+CT_max*v2o];

    if (TV_1[m] == v2o) {
    X_11 = X_1[TV_1[m]];
    X_12 = X_2[TV_1[m]];
    X_13 = X_3[TV_1[m]];

    X_21 = X_1[TV_2[m]];
    X_22 = X_2[TV_2[m]];
    X_23 = X_3[TV_2[m]];

    X_31 = X_1[TV_3[m]];
    X_32 = X_2[TV_3[m]];
    X_33 = X_3[TV_3[m]];

    v2 = TV_2[m];
    v3 = TV_3[m];
    }
    else if (TV_2[m] == v2o) {
    X_11 = X_1[TV_2[m]];
    X_12 = X_2[TV_2[m]];
    X_13 = X_3[TV_2[m]];

    X_21 = X_1[TV_3[m]];
    X_22 = X_2[TV_3[m]];
    X_23 = X_3[TV_3[m]];

    X_31 = X_1[TV_1[m]];
    X_32 = X_2[TV_1[m]];
    X_33 = X_3[TV_1[m]];

    v2 = TV_3[m];
    v3 = TV_1[m];
    }
    else {
    X_11 = X_1[TV_3[m]];
    X_12 = X_2[TV_3[m]];
    X_13 = X_3[TV_3[m]];

    X_21 = X_1[TV_1[m]];
    X_22 = X_2[TV_1[m]];
    X_23 = X_3[TV_1[m]];

    X_31 = X_1[TV_2[m]];
    X_32 = X_2[TV_2[m]];
    X_33 = X_3[TV_2[m]];

    v2 = TV_1[m];
    v3 = TV_2[m];
    }
    //compute derivatives of unit normal

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    A1 += 0.5*n1;
    A2 += 0.5*n2;
    A3 += 0.5*n3;

    norm = sqrt(n1*n1+n2*n2+n3*n3);

    area += 1.0/6.0*norm;

    n1 = n1/norm;
    n2 = n2/norm;
    n3 = n3/norm;

    a1 = X_21-X_31;
    a2 = X_22-X_32;
    a3 = X_23-X_33;

    b1 = n2*a3-n3*a2;
    b2 = n3*a1-n1*a3;
    b3 = n1*a2-n2*a1;

    H1 += 0.5*b1; 
    H2 += 0.5*b2; 
    H3 += 0.5*b3; 

    l += 1;
    }
    //compute derivatives of unit normal

    if (TV_1[k] == v2o) {
    X_11 = X_1[TV_1[k]];
    X_12 = X_2[TV_1[k]];
    X_13 = X_3[TV_1[k]];

    X_21 = X_1[TV_2[k]];
    X_22 = X_2[TV_2[k]];
    X_23 = X_3[TV_2[k]];

    X_31 = X_1[TV_3[k]];
    X_32 = X_2[TV_3[k]];
    X_33 = X_3[TV_3[k]];
    }
    else if (TV_2[k] == v2o) {
    X_11 = X_1[TV_2[k]];
    X_12 = X_2[TV_2[k]];
    X_13 = X_3[TV_2[k]];

    X_21 = X_1[TV_3[k]];
    X_22 = X_2[TV_3[k]];
    X_23 = X_3[TV_3[k]];

    X_31 = X_1[TV_1[k]];
    X_32 = X_2[TV_1[k]];
    X_33 = X_3[TV_1[k]];
    }
    else {
    X_11 = X_1[TV_3[k]];
    X_12 = X_2[TV_3[k]];
    X_13 = X_3[TV_3[k]];

    X_21 = X_1[TV_1[k]];
    X_22 = X_2[TV_1[k]];
    X_23 = X_3[TV_1[k]];

    X_31 = X_1[TV_2[k]];
    X_32 = X_2[TV_2[k]];
    X_33 = X_3[TV_2[k]];
    }

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    norm = sqrt(n1*n1+n2*n2+n3*n3);

    n1 = n1/norm;
    n2 = n2/norm;
    n3 = n3/norm;

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = 1.0;
    b2 = 0.0;
    b3 = 0.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    c1 = -1.0;
    c2 = 0.0;
    c3 = 0.0;

    l1 = n2*c3-n3*c2;
    l2 = n3*c1-n1*c3;
    l3 = n1*c2-n2*c1;

    dH_11_v3 = 0.5*(m1+l1);
    dH_21_v3 = 0.5*(m2+l2);
    dH_31_v3 = 0.5*(m3+l3);

    b1 = 0.0;
    b2 = 1.0;
    b3 = 0.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    c1 = 0.0;
    c2 = -1.0;
    c3 = 0.0;

    l1 = n2*c3-n3*c2;
    l2 = n3*c1-n1*c3;
    l3 = n1*c2-n2*c1;

    dH_12_v3 = 0.5*(m1+l1);
    dH_22_v3 = 0.5*(m2+l2);
    dH_32_v3 = 0.5*(m3+l3);

    b1 = 0.0;
    b2 = 0.0;
    b3 = 1.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    c1 = 0.0;
    c2 = 0.0;
    c3 = -1.0;

    l1 = n2*c3-n3*c2;
    l2 = n3*c1-n1*c3;
    l3 = n1*c2-n2*c1;

    dH_13_v3 = 0.5*(m1+l1);
    dH_23_v3 = 0.5*(m2+l2);
    dH_33_v3 = 0.5*(m3+l3);

    a1 = 1.0;
    a2 = 0.0;
    a3 = 0.0;

    b1 = X_11-X_21;
    b2 = X_12-X_22;
    b3 = X_13-X_23;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    dA_11 = 0.5*m1; 
    dA_21 = 0.5*m2; 
    dA_31 = 0.5*m3; 

    a1 = 0.0;
    a2 = 1.0;
    a3 = 0.0;

    b1 = X_11-X_21;
    b2 = X_12-X_22;
    b3 = X_13-X_23;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    dA_12 = 0.5*m1; 
    dA_22 = 0.5*m2; 
    dA_32 = 0.5*m3; 

    a1 = 0.0;
    a2 = 0.0;
    a3 = 1.0;

    b1 = X_11-X_21;
    b2 = X_12-X_22;
    b3 = X_13-X_23;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    dA_13 = 0.5*m1; 
    dA_23 = 0.5*m2; 
    dA_33 = 0.5*m3; 

    b1 = X_11-X_21;
    b2 = X_12-X_22;
    b3 = X_13-X_23;

    a1 = n2*b3-n3*b2;
    a2 = n3*b1-n1*b3;
    a3 = n1*b2-n2*b1;

    //if (v2o == 7) {
    m1 = H1*dH_11_v3+H2*dH_21_v3+H3*dH_31_v3;
    m2 = A1*A1+A2*A2+A3*A3;
    m3 = H1*H1+H2*H2+H3*H3;
    c1 = A1*dA_11+A2*dA_21+A3*dA_31;
    F_1[i] -= k_curv*(2.0*area*(m1*m2-m3*c1)/(m2*m2)-1.0/6.0*a1*m3/m2);
    //F_1[i] += 2.0*m1;
    //F_1[i] += 2.0*H1*dH_11_v3;
    //F_1[i] += dH_11_v3;
    //F_1[i] += dH_31_v3;

    m1 = H1*dH_12_v3+H2*dH_22_v3+H3*dH_32_v3;
    c1 = A1*dA_12+A2*dA_22+A3*dA_32;
    F_2[i] -= k_curv*(2.0*area*(m1*m2-m3*c1)/(m2*m2)-1.0/6.0*a2*m3/m2);
    //F_2[i] += 2.0*m1;
    //F_2[i] += 2.0*H1*dH_12_v3;
    //F_2[i] += dH_12_v3;
    //F_2[i] += dH_32_v3;

    m1 = H1*dH_13_v3+H2*dH_23_v3+H3*dH_33_v3;
    c1 = A1*dA_13+A2*dA_23+A3*dA_33;
    F_3[i] -= k_curv*(2.0*area*(m1*m2-m3*c1)/(m2*m2)-1.0/6.0*a3*m3/m2);
    //F_3[i] += 2.0*m1;
    //F_3[i] += 2.0*H1*dH_13_v3;
    //F_3[i] += dH_13_v3;
    //F_3[i] += dH_33_v3;
    //}

    A1 = 0;
    A2 = 0;
    A3 = 0;

    H1 = 0;
    H2 = 0;
    H3 = 0;

    area = 0;

    l = 0;
    while (l < CT_max && CT[l+CT_max*v3o] != -1) { 
    m = CT[l+CT_max*v3o];

    if (TV_1[m] == v3o) {
    X_11 = X_1[TV_1[m]];
    X_12 = X_2[TV_1[m]];
    X_13 = X_3[TV_1[m]];

    X_21 = X_1[TV_2[m]];
    X_22 = X_2[TV_2[m]];
    X_23 = X_3[TV_2[m]];

    X_31 = X_1[TV_3[m]];
    X_32 = X_2[TV_3[m]];
    X_33 = X_3[TV_3[m]];

    v2 = TV_2[m];
    v3 = TV_3[m];
    }
    else if (TV_2[m] == v3o) {
    X_11 = X_1[TV_2[m]];
    X_12 = X_2[TV_2[m]];
    X_13 = X_3[TV_2[m]];

    X_21 = X_1[TV_3[m]];
    X_22 = X_2[TV_3[m]];
    X_23 = X_3[TV_3[m]];

    X_31 = X_1[TV_1[m]];
    X_32 = X_2[TV_1[m]];
    X_33 = X_3[TV_1[m]];

    v2 = TV_3[m];
    v3 = TV_1[m];
    }
    else {
    X_11 = X_1[TV_3[m]];
    X_12 = X_2[TV_3[m]];
    X_13 = X_3[TV_3[m]];

    X_21 = X_1[TV_1[m]];
    X_22 = X_2[TV_1[m]];
    X_23 = X_3[TV_1[m]];

    X_31 = X_1[TV_2[m]];
    X_32 = X_2[TV_2[m]];
    X_33 = X_3[TV_2[m]];

    v2 = TV_1[m];
    v3 = TV_2[m];
    }
    //compute derivatives of unit normal

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    A1 += 0.5*n1;
    A2 += 0.5*n2;
    A3 += 0.5*n3;

    norm = sqrt(n1*n1+n2*n2+n3*n3);

    area += 1.0/6.0*norm;

    n1 = n1/norm;
    n2 = n2/norm;
    n3 = n3/norm;

    a1 = X_21-X_31;
    a2 = X_22-X_32;
    a3 = X_23-X_33;

    b1 = n2*a3-n3*a2;
    b2 = n3*a1-n1*a3;
    b3 = n1*a2-n2*a1;

    H1 += 0.5*b1; 
    H2 += 0.5*b2; 
    H3 += 0.5*b3; 

    l += 1;
    }
    //compute derivatives of unit normal

    if (TV_1[k] == v3o) {
    X_11 = X_1[TV_1[k]];
    X_12 = X_2[TV_1[k]];
    X_13 = X_3[TV_1[k]];

    X_21 = X_1[TV_2[k]];
    X_22 = X_2[TV_2[k]];
    X_23 = X_3[TV_2[k]];

    X_31 = X_1[TV_3[k]];
    X_32 = X_2[TV_3[k]];
    X_33 = X_3[TV_3[k]];
    }
    else if (TV_2[k] == v3o) {
    X_11 = X_1[TV_2[k]];
    X_12 = X_2[TV_2[k]];
    X_13 = X_3[TV_2[k]];

    X_21 = X_1[TV_3[k]];
    X_22 = X_2[TV_3[k]];
    X_23 = X_3[TV_3[k]];

    X_31 = X_1[TV_1[k]];
    X_32 = X_2[TV_1[k]];
    X_33 = X_3[TV_1[k]];
    }
    else {
    X_11 = X_1[TV_3[k]];
    X_12 = X_2[TV_3[k]];
    X_13 = X_3[TV_3[k]];

    X_21 = X_1[TV_1[k]];
    X_22 = X_2[TV_1[k]];
    X_23 = X_3[TV_1[k]];

    X_31 = X_1[TV_2[k]];
    X_32 = X_2[TV_2[k]];
    X_33 = X_3[TV_2[k]];
    }

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    norm = sqrt(n1*n1+n2*n2+n3*n3);

    n1 = n1/norm;
    n2 = n2/norm;
    n3 = n3/norm;

    a1 = X_11-X_31;
    a2 = X_12-X_32;
    a3 = X_13-X_33;

    b1 = 1.0;
    b2 = 0.0;
    b3 = 0.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    c1 = 1.0;
    c2 = 0.0;
    c3 = 0.0;

    l1 = n2*c3-n3*c2;
    l2 = n3*c1-n1*c3;
    l3 = n1*c2-n2*c1;

    dH_11_v2 = 0.5*(m1+l1);
    dH_21_v2 = 0.5*(m2+l2);
    dH_31_v2 = 0.5*(m3+l3);

    b1 = 0.0;
    b2 = 1.0;
    b3 = 0.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    c1 = 0.0;
    c2 = 1.0;
    c3 = 0.0;

    l1 = n2*c3-n3*c2;
    l2 = n3*c1-n1*c3;
    l3 = n1*c2-n2*c1;

    dH_12_v2 = 0.5*(m1+l1);
    dH_22_v2 = 0.5*(m2+l2);
    dH_32_v2 = 0.5*(m3+l3);

    b1 = 0.0;
    b2 = 0.0;
    b3 = 1.0;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    c1 = 1.0/norm*(m1-n1*(n1*m1+n2*m2+n3*m3)); 
    c2 = 1.0/norm*(m2-n2*(n1*m1+n2*m2+n3*m3)); 
    c3 = 1.0/norm*(m3-n3*(n1*m1+n2*m2+n3*m3)); 

    b1 = X_21-X_31;
    b2 = X_22-X_32;
    b3 = X_23-X_33;

    m1 = c2*b3-c3*b2;
    m2 = c3*b1-c1*b3;
    m3 = c1*b2-c2*b1;

    c1 = 0.0;
    c2 = 0.0;
    c3 = 1.0;

    l1 = n2*c3-n3*c2;
    l2 = n3*c1-n1*c3;
    l3 = n1*c2-n2*c1;

    dH_13_v2 = 0.5*(m1+l1);
    dH_23_v2 = 0.5*(m2+l2);
    dH_33_v2 = 0.5*(m3+l3);

    a1 = 1.0;
    a2 = 0.0;
    a3 = 0.0;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    dA_11 = 0.5*m1; 
    dA_21 = 0.5*m2; 
    dA_31 = 0.5*m3; 

    a1 = 0.0;
    a2 = 1.0;
    a3 = 0.0;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    dA_12 = 0.5*m1; 
    dA_22 = 0.5*m2; 
    dA_32 = 0.5*m3; 

    a1 = 0.0;
    a2 = 0.0;
    a3 = 1.0;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    m1 = a2*b3-a3*b2;
    m2 = a3*b1-a1*b3;
    m3 = a1*b2-a2*b1;

    dA_13 = 0.5*m1; 
    dA_23 = 0.5*m2; 
    dA_33 = 0.5*m3; 

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    a1 = n2*b3-n3*b2;
    a2 = n3*b1-n1*b3;
    a3 = n1*b2-n2*b1;

    //if (v3o == 7) {
    m1 = H1*dH_11_v2+H2*dH_21_v2+H3*dH_31_v2;
    m2 = A1*A1+A2*A2+A3*A3;
    m3 = H1*H1+H2*H2+H3*H3;
    c1 = A1*dA_11+A2*dA_21+A3*dA_31;
    F_1[i] -= k_curv*(2.0*area*(m1*m2-m3*c1)/(m2*m2)-1.0/6.0*a1*m3/m2);
    //F_1[i] += 2.0*m1;
    //F_1[i] += 2.0*H1*dH_11_v2;
    //F_1[i] += dH_11_v2;
    //F_1[i] += dH_31_v2;

    m1 = H1*dH_12_v2+H2*dH_22_v2+H3*dH_32_v2;
    c1 = A1*dA_12+A2*dA_22+A3*dA_32;
    F_2[i] -= k_curv*(2.0*area*(m1*m2-m3*c1)/(m2*m2)-1.0/6.0*a2*m3/m2);
    //F_2[i] += 2.0*m1;
    //F_2[i] += 2.0*H1*dH_12_v2;
    //F_2[i] += dH_12_v2;
    //F_2[i] += dH_32_v2;

    m1 = H1*dH_13_v2+H2*dH_23_v2+H3*dH_33_v2;
    c1 = A1*dA_13+A2*dA_23+A3*dA_33;
    F_3[i] -= k_curv*(2.0*area*(m1*m2-m3*c1)/(m2*m2)-1.0/6.0*a3*m3/m2);
    //F_3[i] += 2.0*m1;
    //F_3[i] += 2.0*H1*dH_13_v2;
    //F_3[i] += dH_13_v2;
    //F_3[i] += dH_33_v2;
    //}

    j += 1;
    }
    }
    __kernel void calc_curv(__global const float *X_1, __global const float *X_2, __global const float *X_3, __global const unsigned *TV_1, __global const unsigned *TV_2, __global const unsigned *TV_3, __global const int *CT, const unsigned N_tri, const unsigned CT_max, __global float *F_1, __global float *F_2, __global float *F_3)
    { 
    unsigned i = get_global_id(0);

    float X_11, X_12, X_13;
    float X_21, X_22, X_23;
    float X_31, X_32, X_33;

    float n1, n2, n3, norm;
    float a1, a2, a3;
    float b1, b2, b3;

    unsigned k;
    unsigned j = 0;
    while (j < CT_max && CT[j+CT_max*i] != -1) { 
    k = CT[j+CT_max*i];

    if (TV_1[k] == i) {
    X_11 = X_1[TV_1[k]];
    X_12 = X_2[TV_1[k]];
    X_13 = X_3[TV_1[k]];

    X_21 = X_1[TV_2[k]];
    X_22 = X_2[TV_2[k]];
    X_23 = X_3[TV_2[k]];

    X_31 = X_1[TV_3[k]];
    X_32 = X_2[TV_3[k]];
    X_33 = X_3[TV_3[k]];
    }
    else if (TV_2[k] == i) {
    X_11 = X_1[TV_2[k]];
    X_12 = X_2[TV_2[k]];
    X_13 = X_3[TV_2[k]];

    X_21 = X_1[TV_3[k]];
    X_22 = X_2[TV_3[k]];
    X_23 = X_3[TV_3[k]];

    X_31 = X_1[TV_1[k]];
    X_32 = X_2[TV_1[k]];
    X_33 = X_3[TV_1[k]];
    }
    else {
    X_11 = X_1[TV_3[k]];
    X_12 = X_2[TV_3[k]];
    X_13 = X_3[TV_3[k]];

    X_21 = X_1[TV_1[k]];
    X_22 = X_2[TV_1[k]];
    X_23 = X_3[TV_1[k]];

    X_31 = X_1[TV_2[k]];
    X_32 = X_2[TV_2[k]];
    X_33 = X_3[TV_2[k]];
    }

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    norm = sqrt(n1*n1+n2*n2+n3*n3);

    n1 = n1/norm;
    n2 = n2/norm;
    n3 = n3/norm;

    a1 = X_21-X_31;
    a2 = X_22-X_32;
    a3 = X_23-X_33;

    b1 = n2*a3-n3*a2;
    b2 = n3*a1-n1*a3;
    b3 = n1*a2-n2*a1;

    F_1[i] += 0.5*b1; 
    F_2[i] += 0.5*b2; 
    F_3[i] += 0.5*b3; 
    //F_1[i] += b1; 
    //F_2[i] += b2; 
    //F_3[i] += b3; 

    //test normals 
    //F_1[i] += n1; 
    //F_2[i] += n2; 
    //F_3[i] += n3; 

    j += 1;
    }
    }
    __kernel void calc_energy_curv(__global const float *X_1, __global const float *X_2, __global const float *X_3, __global const unsigned *TV_1, __global const unsigned *TV_2, __global const unsigned *TV_3, __global const int *CT, const unsigned CT_max, const unsigned b_q, const unsigned N_r,  const float k_curv, __global float *en)
    { 
    float X_11, X_12, X_13;
    float X_21, X_22, X_23;
    float X_31, X_32, X_33;

    float n1, n2, n3, norm;
    float a1, a2, a3;
    float b1, b2, b3;

    float H1, H2, H3;
    float A1, A2, A3;
    float area;

    unsigned j, k;
    
    for (unsigned i=N_r; i<b_q; i++) {
    //debugging -- only do first vertex
    //for (unsigned i=0; i<1; i++) {
    //unsigned i=7;
    //calc H_p, A_p, area

    j = 0;

    A1 = 0;
    A2 = 0;
    A3 = 0;

    H1 = 0;
    H2 = 0;
    H3 = 0;

    area = 0;

    while (j < CT_max && CT[j+CT_max*i] != -1) { 
    k = CT[j+CT_max*i];

    if (TV_1[k] == i) {
    X_11 = X_1[TV_1[k]];
    X_12 = X_2[TV_1[k]];
    X_13 = X_3[TV_1[k]];

    X_21 = X_1[TV_2[k]];
    X_22 = X_2[TV_2[k]];
    X_23 = X_3[TV_2[k]];

    X_31 = X_1[TV_3[k]];
    X_32 = X_2[TV_3[k]];
    X_33 = X_3[TV_3[k]];
    }
    else if (TV_2[k] == i) {
    X_11 = X_1[TV_2[k]];
    X_12 = X_2[TV_2[k]];
    X_13 = X_3[TV_2[k]];

    X_21 = X_1[TV_3[k]];
    X_22 = X_2[TV_3[k]];
    X_23 = X_3[TV_3[k]];

    X_31 = X_1[TV_1[k]];
    X_32 = X_2[TV_1[k]];
    X_33 = X_3[TV_1[k]];
    }
    else {
    X_11 = X_1[TV_3[k]];
    X_12 = X_2[TV_3[k]];
    X_13 = X_3[TV_3[k]];

    X_21 = X_1[TV_1[k]];
    X_22 = X_2[TV_1[k]];
    X_23 = X_3[TV_1[k]];

    X_31 = X_1[TV_2[k]];
    X_32 = X_2[TV_2[k]];
    X_33 = X_3[TV_2[k]];
    }

    a1 = X_21-X_11;
    a2 = X_22-X_12;
    a3 = X_23-X_13;

    b1 = X_31-X_11;
    b2 = X_32-X_12;
    b3 = X_33-X_13;

    n1 = a2*b3-a3*b2;
    n2 = a3*b1-a1*b3;
    n3 = a1*b2-a2*b1;

    A1 += 0.5*n1;
    A2 += 0.5*n2;
    A3 += 0.5*n3;

    norm = sqrt(n1*n1+n2*n2+n3*n3);

    area += 1.0/6.0*norm;

    n1 = n1/norm;
    n2 = n2/norm;
    n3 = n3/norm;

    a1 = X_21-X_31;
    a2 = X_22-X_32;
    a3 = X_23-X_33;

    b1 = n2*a3-n3*a2;
    b2 = n3*a1-n1*a3;
    b3 = n1*a2-n2*a1;

    H1 += 0.5*b1; 
    H2 += 0.5*b2; 
    H3 += 0.5*b3; 

    j += 1;
    }

    en[0] += k_curv*(H1*H1+H2*H2+H3*H3)/(A1*A1+A2*A2+A3*A3)*area; 
    //en[0] += (H1*H1+H2*H2+H3*H3)/(A1*A1+A2*A2+A3*A3); 
    //en[0] += (H1*H1+H2*H2+H3*H3); 
    //en[0] += H3; 
    }
    }
    """).build()

calc_lagF_test_kernel = ib_prg.calc_lagF_test
calc_lagF_test_kernel.set_scalar_arg_dtypes([None]*6)

calc_energy_test_kernel = ib_prg.calc_energy_test
calc_energy_test_kernel.set_scalar_arg_dtypes([None]*4)

calc_lagF_teth_kernel = ib_prg.calc_lagF_teth
calc_lagF_teth_kernel.set_scalar_arg_dtypes([None]*7 + [np.float32]*2 + [None]*3)

calc_lagF_area_kernel = ib_prg.calc_lagF_area
calc_lagF_area_kernel.set_scalar_arg_dtypes([None]*8 + [np.uint32] + [np.float32]*1 + [None]*3)

calc_lagF_area_old_kernel = ib_prg.calc_lagF_area_old
calc_lagF_area_old_kernel.set_scalar_arg_dtypes([None]*7 + [np.float32]*1 + [np.uint32] + [None]*3)

calc_energy_area_kernel = ib_prg.calc_energy_area
calc_energy_area_kernel.set_scalar_arg_dtypes([None]*7 + [np.float32]*1 + [np.uint32] + [None])

calc_energy_curv_kernel = ib_prg.calc_energy_curv
calc_energy_curv_kernel.set_scalar_arg_dtypes([None]*7 + [np.uint32]*3 + [np.float32] + [None])

calc_energy_hook_kernel = ib_prg.calc_energy_hook
calc_energy_hook_kernel.set_scalar_arg_dtypes([None]*10 + [np.float32]*2 + [np.uint32] + [None])

calc_lagF_hook_kernel = ib_prg.calc_lagF_hook
calc_lagF_hook_kernel.set_scalar_arg_dtypes([None]*11 + [np.uint32]*1 + [np.float32]*2 + [None]*3)

calc_curv_kernel = ib_prg.calc_curv
calc_curv_kernel.set_scalar_arg_dtypes([None]*7 + [np.uint32]*2 + [None]*3)

calc_F_curv_kernel = ib_prg.calc_F_curv
calc_F_curv_kernel.set_scalar_arg_dtypes([None]*7 + [np.uint32]*2 + [np.float32] + [None]*3)

div_kernel = prg.div
div_kernel.set_scalar_arg_dtypes([None]*3 + [np.float32, np.uint32] + [None])

L_adj_1_kernel = prg.L_adj_1
L_adj_1_kernel.set_scalar_arg_dtypes([None])

L_adj_2_kernel = prg.L_adj_2
L_adj_2_kernel.set_scalar_arg_dtypes([None])

p_filt_kernel = prg.p_filt
p_filt_kernel.set_scalar_arg_dtypes([None])

nyq_filt_kernel = prg.nyq_filt
nyq_filt_kernel.set_scalar_arg_dtypes([None] + [np.uint32])

solve_kernel = solve_prg.solve
solve_kernel.set_scalar_arg_dtypes([None]*7 + [np.float32]*3 + [np.uint32] + [None]*3)

grad_kernel = prg.grad
grad_kernel.set_scalar_arg_dtypes([None]*1 + [np.float32, np.uint32] + [None]*3)

ss_conv_kernel = prg.ss_conv
ss_conv_kernel.set_scalar_arg_dtypes([None]*3 + [np.float32, np.uint32] + [None]*3)

interp_kernel = ib_prg.interp
interp_kernel.set_scalar_arg_dtypes([None]*6 + [np.uint32, np.float32] + [None]*3)
spread_kernel = ib_prg.spread
spread_kernel.set_scalar_arg_dtypes([None]*12 + [np.uint32] + [np.float32]*2 + [np.uint32]*3 + [None]*3)
updaten_kernel = ib_prg.updaten
updaten_kernel.set_scalar_arg_dtypes([None]*9 + [np.uint32] + [np.float32] + [np.uint32]*3)

for ii in range(start_size,end_size+1): 
    #set up grid
    N = 2**ii
    dx = 1.0/N
    rho = 1.0

    x_stag = np.arange(-0.5, 0.5, dx)
    xx_1_stag = np.tile(x_stag, (N, N, 1))
    xx_2_stag = np.tile(x_stag.reshape(N,1), (N, 1, N))
    xx_3_stag = np.tile(x_stag.reshape(N,1,1), (1, N, N))

    x_c = np.arange(-0.5+dx/2, 0.5+dx/2, dx)
    xx_1_c = np.tile(x_c, (N, N, 1))
    xx_2_c = np.tile(x_c.reshape(N,1), (N, 1, N))
    xx_3_c = np.tile(x_c.reshape(N,1,1), (1, N, N))
    
    if PR_INT:
        mesh3 = np.vstack((xx_1_c[np.newaxis],xx_2_c[np.newaxis],xx_3_c[np.newaxis]))

    mu = 0.1
    dt = 0.5*dx
    clock_max = np.int(np.round(20.0/dt,0))
    clock_max = 1
    print clock_max

    #set up Lagrangian parameters
    N_r = 2**6 
    #N_s = 4*N
    #N_r = 3*N/8
    N_s = 0 
    b_q = N_r
    dr = 1./N_r
    ds = 1.
    dtheta = dr
    #a_lag = 0.2
    #b_lag = 0.25
    a_lag = 0.225
    b_lag = 0.225
    g_lag = 0.0625

    #set up Lagrangian grid
    r_lag = np.arange(dr/2, 1, dr)
    s_lag = np.arange(ds/2, 1, ds)
    rr_lag, ss_lag = np.meshgrid(r_lag, s_lag)
    rr_lag = rr_lag.reshape(b_q,1)
    #ss_lag = ss_lag.reshape(b_q,1)

    i_lag = np.arange(0, b_q)
    ip_s_lag = np.remainder(i_lag+N_r, b_q)
    im_s_lag = np.remainder(i_lag-N_r, b_q)

    ruler = np.arange(0,1,1./np.sqrt(N_r))
    V = np.tile(ruler, (1,np.sqrt(N_r)))
    U = V.reshape(np.sqrt(N_r),np.sqrt(N_r)).copy()
    U = U.T.reshape(N_r,1).copy()
    V = V.T.copy()

    szT = 2*N_r
    TV = np.zeros((szT,3))

    #I suspect there's a more intuitive way to do this; i.e. calculate i and j new
    for i in range(0,np.sqrt(N_r).astype(int)):
        for j in range(0,np.sqrt(N_r).astype(int)):
            TV[2*(j+np.sqrt(N_r)*i),0] = j+np.sqrt(N_r)*i 
            TV[2*(j+np.sqrt(N_r)*i),1] = (np.mod(np.mod(j+np.sqrt(N_r)*i+1,N_r),np.sqrt(N_r))+np.sqrt(N_r)*np.floor(np.mod(j+np.sqrt(N_r)*i,N_r)/np.sqrt(N_r)))
            TV[2*(j+np.sqrt(N_r)*i),2] = np.mod(j+np.sqrt(N_r)*i+np.sqrt(N_r),N_r) 
            TV[2*(j+np.sqrt(N_r)*i)+1,0] = np.mod(j+np.sqrt(N_r)*i+np.sqrt(N_r),N_r) 
            TV[2*(j+np.sqrt(N_r)*i)+1,1] = (np.mod(np.mod(j+np.sqrt(N_r)*i+1,N_r),np.sqrt(N_r))+np.sqrt(N_r)*np.floor(np.mod(j+np.sqrt(N_r)*i,N_r)/np.sqrt(N_r)))
            TV[2*(j+np.sqrt(N_r)*i)+1,2] = np.mod(np.mod(np.mod(j+np.sqrt(N_r)*i+1,N_r),np.sqrt(N_r))+np.sqrt(N_r)*np.floor(np.mod(j+np.sqrt(N_r)*i,N_r)/np.sqrt(N_r))+np.sqrt(N_r),N_r)

    #X_1 = (a_lag+g_lag*(rr_lag-0.5))*np.cos(2*pi*ss_lag)
    #X_2 = (b_lag+g_lag*(rr_lag-0.5))*np.sin(2*pi*ss_lag)
    #X_3 = np.zeros((b_q,1)) 

    U = 2*pi*U
    V = 2*pi*V

    #X_1 = 1./12.*np.cos(U)*(2+np.cos(V))
    #X_2 = 1./12.*np.sin(U)*(2+np.cos(V))
    #X_3 = 1./4.*np.sin(V)
    X_1 = -0.25+0.5/(2.*pi)*V
    X_2 = 0.25*np.cos(U)
    X_3 = 0.25*np.sin(U)

    #include for tethering
    k_teth = 1.0
    N_teth = N_r
    X_1_teth = X_1
    X_2_teth = X_2
    X_3_teth = X_3
    i_teth = i_lag

    ###debugging
    #TV = []
    szT = 0
    b_q = 0

    #add sphere
    vertex_array, tri_array = create_unit_sphere(2)
    vertex_array = 0.125*(vertex_array)
    #X_1 = np.vstack((X_1, vertex_array[:,0].reshape(vertex_array.shape[0],1)))
    #X_2 = np.vstack((X_2, vertex_array[:,1].reshape(vertex_array.shape[0],1)))
    #X_3 = np.vstack((X_3, vertex_array[:,2].reshape(vertex_array.shape[0],1)))
    X_1 = vertex_array[:,0].reshape(vertex_array.shape[0],1)
    X_2 = vertex_array[:,1].reshape(vertex_array.shape[0],1)
    X_3 = vertex_array[:,2].reshape(vertex_array.shape[0],1)
    X_ref_1 = X_1 + 0.1*np.random.rand(X_1.shape[0],1)
    X_ref_2 = X_2 + 0.1*np.random.rand(X_2.shape[0],1)
    X_ref_3 = X_3 + 0.1*np.random.rand(X_3.shape[0],1)
    #TV = np.vstack((TV, tri_array+N_r))
    TV = tri_array
    szT = szT + tri_array.shape[0]
    #szT = tri_array.shape[0]
    b_q = b_q+vertex_array.shape[0]
    #b_q = vertex_array.shape[0]

    #include for area force
    k_area = 1.0 
    N_tri = szT 
    A_0 = np.zeros((szT,1))  
    for i in range(0,szT):
        x11 = X_1[TV[i,0]]
        x12 = X_2[TV[i,0]]
        x13 = X_3[TV[i,0]]
        x21 = X_1[TV[i,1]]
        x22 = X_2[TV[i,1]]
        x23 = X_3[TV[i,1]]
        x31 = X_1[TV[i,2]]
        x32 = X_2[TV[i,2]]
        x33 = X_3[TV[i,2]]
        b1 = x31-x11
        b2 = x32-x12
        b3 = x33-x13
        a1 = x21-x11
        a2 = x22-x12
        a3 = x23-x13
        n1 = a2*b3-a3*b2
        n2 = a3*b1-a1*b3
        n3 = a1*b2-a2*b1
        A_0[i] = 0.5*np.sqrt(n1*n1+n2*n2+n3*n3)

    TV = TV[np.nonzero(A_0 != 0.0)[0],:]
    temp = int(sum(A_0 == 0.0)[0])
    N_tri = N_tri - temp 
    A_0 = A_0[A_0 != 0.0]
    A_0 = 1.2*A_0
    #print TV

    #neo-Hookean parameters
    k_bulk = 1.0
    k_shear = 1.0

    #include for mean curvature
    k_curv = 0.5
    nt = np.zeros((b_q, 1)).astype(np.int32)
    for i in range(0,b_q):
        for j in range(0, N_tri):
            if (i == TV[j,0] or i == TV[j,1] or i == TV[j,2]):
                nt[i] = nt[i] + 1

    CT = -1.0*np.ones((b_q,np.max(nt))).astype(np.int32)
    CT_max = np.max(nt).astype(np.uint32)
    nt = np.zeros((b_q, 1)).astype(np.int32)
    for i in range(0, N_tri):
        CT[TV[i,0],nt[TV[i,0]]] = i
        CT[TV[i,1],nt[TV[i,1]]] = i
        CT[TV[i,2],nt[TV[i,2]]] = i
        nt[TV[i,0]] += 1
        nt[TV[i,1]] += 1
        nt[TV[i,2]] += 1

    #include for body force
    body_f = 1.0 
    #body = np.ones((N,N,N))
    body = (np.abs(xx_2_c**2+xx_3_c**2)<0.0625)*np.ones((N,N,N))

    #X_3 = np.sin(2*pi*ss_lag) 

    firstn1 = -1*np.ones((N,N,N))
    nextn1 = -1*np.ones((b_q,1))
    firstn2 = -1*np.ones((N,N,N))
    nextn2 = -1*np.ones((b_q,1))
    firstn3 = -1*np.ones((N,N,N))
    nextn3 = -1*np.ones((b_q,1))

    start_time = time.time()
    for k in range(0,b_q):
        s_1_stag = (X_1[k]+0.5)/dx
        s_2_stag = (X_2[k]+0.5)/dx        
        s_3_stag = (X_3[k]+0.5)/dx        
        i_1_stag = (np.floor(s_1_stag)).astype(np.uint32)
        i_2_stag = (np.floor(s_2_stag)).astype(np.uint32)
        i_3_stag = (np.floor(s_3_stag)).astype(np.uint32)
        s_1_c = (X_1[k]+0.5-dx/2)/dx;
        s_2_c = (X_2[k]+0.5-dx/2)/dx;        
        s_3_c = (X_3[k]+0.5-dx/2)/dx;        
        i_1_c = (np.remainder(np.floor(s_1_c),N)).astype(np.uint32);
        i_2_c = (np.remainder(np.floor(s_2_c),N)).astype(np.uint32);
        i_3_c = (np.remainder(np.floor(s_3_c),N)).astype(np.uint32);
        if (firstn1[i_3_c,i_2_c,i_1_stag]==-1):
            firstn1[i_3_c,i_2_c,i_1_stag]=k 
        else:
            nextn1[k]=firstn1[i_3_c,i_2_c,i_1_stag]
            firstn1[i_3_c,i_2_c,i_1_stag]=k
        if (firstn2[i_3_c,i_2_stag,i_1_c]==-1):
            firstn2[i_3_c,i_2_stag,i_1_c]=k 
        else:
            nextn2[k]=firstn2[i_3_c,i_2_stag,i_1_c]
            firstn2[i_3_c,i_2_stag,i_1_c]=k
        if (firstn3[i_3_stag,i_2_c,i_1_c]==-1):
            firstn3[i_3_stag,i_2_c,i_1_c]=k 
        else:
            nextn3[k]=firstn3[i_3_stag,i_2_c,i_1_c]
            firstn3[i_3_stag,i_2_c,i_1_c]=k
    print 'time spent binning points is', time.time()-start_time, 'seconds'

    #move data to gpu

    L_tf = calc_transf(dx)

    #u_1_soln = 2*np.cos(2*pi*xx_1_stag)*np.sin(4*pi*xx_2_c)
    #u_2_soln = -np.sin(2*pi*xx_1_c)*np.cos(4*pi*xx_2_stag)
    #u_1_soln = -np.sin(2*pi*xx_2_c)*np.cos(2*pi*xx_1_stag)
    #u_2_soln = np.sin(2*pi*xx_1_c)*np.cos(2*pi*xx_2_stag)
    u_1_soln = np.zeros((N,N,N)) #initial conditions
    u_2_soln = np.zeros((N,N,N))
    u_3_soln = np.zeros((N,N,N))
    #u_3_soln = np.cos(2*pi*xx_1_c)*np.sin(4*pi*xx_2_c)

    #for testing
    Z_1 = np.random.rand(X_1.shape[0],1)
    Z_2 = np.random.rand(X_1.shape[0],1)
    Z_3 = np.random.rand(X_1.shape[0],1)
    en = np.zeros((1,1))

    #debugging hack
    #Z_1 = np.vstack((np.random.rand(1,1),np.zeros((X_1.shape[0]-1,1))))
    #Z_2 = np.vstack((np.random.rand(1,1),np.zeros((X_1.shape[0]-1,1))))
    #Z_3 = np.vstack((np.random.rand(1,1),np.zeros((X_1.shape[0]-1,1))))

    #move data to gpu
    start_time = time.time()
    plan = Plan((N, N, N), queue=queue)
    print 'time spent making plan is', time.time()-start_time, 'seconds'

    u_1_gpu = cl_array.to_device(queue, u_1_soln.astype(np.float32))
    u_2_gpu = cl_array.to_device(queue, u_2_soln.astype(np.float32))
    u_3_gpu = cl_array.to_device(queue, u_3_soln.astype(np.float32))
    u_1_tf_gpu = cl_array.to_device(queue, u_1_soln.astype(np.complex64))
    u_2_tf_gpu = cl_array.to_device(queue, u_2_soln.astype(np.complex64))
    u_3_tf_gpu = cl_array.to_device(queue, u_3_soln.astype(np.complex64))
    L_tf_gpu = cl_array.to_device(queue, L_tf.astype(np.complex64))
    f_1_gpu = cl_array.empty_like(u_1_gpu) 
    f_2_gpu = cl_array.empty_like(u_1_gpu) 
    f_3_gpu = cl_array.empty_like(u_1_gpu) 
    #test_1_gpu = cl_array.empty_like(u_1_gpu) 
    #test_2_gpu = cl_array.empty_like(u_1_gpu) 
    #test_3_gpu = cl_array.empty_like(u_1_gpu) 
    f_1_tf_gpu = cl_array.empty_like(u_1_tf_gpu) 
    f_2_tf_gpu = cl_array.empty_like(u_1_tf_gpu) 
    f_3_tf_gpu = cl_array.empty_like(u_1_tf_gpu) 
    p_gpu = cl_array.empty_like(u_1_gpu) 
    p_tf_gpu = cl_array.empty_like(u_1_tf_gpu) 
    u_1_tilde_gpu = cl_array.empty_like(u_1_gpu) 
    u_2_tilde_gpu = cl_array.empty_like(u_1_gpu) 
    u_3_tilde_gpu = cl_array.empty_like(u_1_gpu) 
    firstn1_gpu = cl_array.to_device(queue, firstn1.astype(np.int32))
    nextn1_gpu = cl_array.to_device(queue, nextn1.astype(np.int32))
    firstn2_gpu = cl_array.to_device(queue, firstn2.astype(np.int32))
    nextn2_gpu = cl_array.to_device(queue, nextn2.astype(np.int32))
    firstn3_gpu = cl_array.to_device(queue, firstn3.astype(np.int32))
    nextn3_gpu = cl_array.to_device(queue, nextn3.astype(np.int32))
    X_1_gpu = cl_array.to_device(queue, X_1.astype(np.float32))
    X_2_gpu = cl_array.to_device(queue, X_2.astype(np.float32))
    X_3_gpu = cl_array.to_device(queue, X_3.astype(np.float32))
    X_ref_1_gpu = cl_array.to_device(queue, X_ref_1.astype(np.float32))
    X_ref_2_gpu = cl_array.to_device(queue, X_ref_2.astype(np.float32))
    X_ref_3_gpu = cl_array.to_device(queue, X_ref_3.astype(np.float32))
    TV_gpu = cl_array.to_device(queue, TV.astype(np.int32))
    TV_1_gpu = cl_array.to_device(queue, TV[:,0].astype(np.uint32))
    TV_2_gpu = cl_array.to_device(queue, TV[:,1].astype(np.uint32))
    TV_3_gpu = cl_array.to_device(queue, TV[:,2].astype(np.uint32))
    X_1_tilde_gpu = cl_array.to_device(queue, X_1.astype(np.float32))
    X_2_tilde_gpu = cl_array.to_device(queue, X_2.astype(np.float32))
    X_3_tilde_gpu = cl_array.to_device(queue, X_3.astype(np.float32))
    rr_lag_gpu = cl_array.to_device(queue, rr_lag.astype(np.float32))
    ip_s_lag_gpu = cl_array.to_device(queue, ip_s_lag.astype(np.uint32))
    im_s_lag_gpu = cl_array.to_device(queue, im_s_lag.astype(np.uint32))
    F_1_gpu = cl_array.empty_like(X_1_gpu) 
    F_2_gpu = cl_array.empty_like(X_1_gpu) 
    F_3_gpu = cl_array.empty_like(X_1_gpu) 
    U_1_gpu = cl_array.empty_like(X_1_gpu) 
    U_2_gpu = cl_array.empty_like(X_1_gpu) 
    U_3_gpu = cl_array.empty_like(X_1_gpu) 
    X_print = X_1.__array__(np.float32)
    X_1_teth_gpu = cl_array.to_device(queue, X_1_teth.astype(np.float32))
    X_2_teth_gpu = cl_array.to_device(queue, X_2_teth.astype(np.float32))
    X_3_teth_gpu = cl_array.to_device(queue, X_3_teth.astype(np.float32))
    i_teth_gpu = cl_array.to_device(queue, i_teth.astype(np.uint32))
    A_0_gpu = cl_array.to_device(queue, A_0.astype(np.float32))
    body_gpu = cl_array.to_device(queue, body.astype(np.float32)) 
    CT_gpu = cl_array.to_device(queue, CT.astype(np.int32)) 

    #for testing
    Z_1_gpu = cl_array.to_device(queue, Z_1.astype(np.float32))
    Z_2_gpu = cl_array.to_device(queue, Z_2.astype(np.float32))
    Z_3_gpu = cl_array.to_device(queue, Z_3.astype(np.float32))
    X_1_new_gpu = cl_array.to_device(queue, Z_1.astype(np.float32))
    X_2_new_gpu = cl_array.to_device(queue, Z_2.astype(np.float32))
    X_3_new_gpu = cl_array.to_device(queue, Z_3.astype(np.float32))
    en_gpu = cl_array.to_device(queue, en.astype(np.float32))
    F_11_gpu = cl_array.empty_like(X_1_gpu) 
    F_12_gpu = cl_array.empty_like(X_1_gpu) 
    F_13_gpu = cl_array.empty_like(X_1_gpu) 
    F_21_gpu = cl_array.empty_like(X_1_gpu) 
    F_22_gpu = cl_array.empty_like(X_1_gpu) 
    F_23_gpu = cl_array.empty_like(X_1_gpu) 
    F_31_gpu = cl_array.empty_like(X_1_gpu) 
    F_32_gpu = cl_array.empty_like(X_1_gpu) 
    F_33_gpu = cl_array.empty_like(X_1_gpu) 

    #solve
    queue.finish()
    start_time = time.time()
    for t_step in range(1, clock_max+1):
        solve(t_step)
        if t_step % 1 == 0:
            print t_step
            print u_1_gpu.get().max()  
            print u_2_gpu.get().max()  
            print u_3_gpu.get().max()  
        if PR_INT:
            if t_step % PR_INT == 0:

                from os.path import join as pjoin
                #vis_u_1 = u_1_gpu.get().reshape(N,N,1)
                vis_u_1 = u_1_gpu.get()
                file_name = "u_1-%04d.vts"%t_step
                path_to_file = pjoin("vis_files", file_name) 
                write_structured_grid(path_to_file, mesh3.reshape(3, N, N, N), 
                point_data=[("u_1", vis_u_1)])

                #vis_u_2 = u_2_gpu.get().reshape(N,N,1)
                vis_u_2 = u_2_gpu.get()
                file_name = "u_2-%04d.vts"%t_step
                path_to_file = pjoin("vis_files", file_name) 
                write_structured_grid(path_to_file, mesh3.reshape(3, N, N, N), 
                point_data=[("u_2", vis_u_2)])

                #vis_p = p_gpu.get()
                #write_structured_grid("p-%04d.vts"%t_step, mesh3, 
                #point_data=[("p", vis_p)])

                vis_X_1 = np.mod(X_1_gpu.get()+0.5,1.0)-0.5
                vis_X_2 = np.mod(X_2_gpu.get()+0.5,1.0)-0.5
                vis_X_3 = np.mod(X_3_gpu.get()+0.5,1.0)-0.5

                vis_X = np.hstack((vis_X_1,vis_X_2,vis_X_3)).copy()
                data = [
                #("F_1", F_1_gpu.get().reshape(b_q).copy()),
                #("F_2", F_2_gpu.get().reshape(b_q).copy()),
                #("F_3", F_3_gpu.get().reshape(b_q).copy())
                ]

                file_name = "X-%04d.vtu"%t_step
                compressor = None

                grid = UnstructuredGrid(
                     (b_q, DataArray("points", vis_X, vector_format=VF_LIST_OF_VECTORS)),
                     cells=np.arange(b_q, dtype=np.uint32),
                     cell_types=np.asarray([VTK_VERTEX] * b_q, dtype=np.uint8))

                for name, field in data:
                   grid.add_pointdata(DataArray(name, field,
                   vector_format=VF_LIST_OF_COMPONENTS))

                from os.path import exists
                path_to_file = pjoin("vis_files", file_name)
                if exists(path_to_file):
                   raise RuntimeError("output file '%s' already exists"
                   % path_to_file)

                outf = open(path_to_file, "w")
                AppendedDataXMLGenerator(compressor)(grid).write(outf)
                outf.close()

                file_name = "tri-%04d.vtu"%t_step
                compressor = None
                cell_data = []
                point_data = []

                grid = UnstructuredGrid(
                    (b_q,
                    DataArray("points", vis_X,
                    vector_format=VF_LIST_OF_VECTORS)),
                    cells=TV_gpu.get().reshape(-1),
                    cell_types=np.asarray([VTK_TRIANGLE] * TV_gpu.get().shape[0], dtype=np.uint32))

                for name, field in point_data:
                    grid.add_pointdata(DataArray(name, field,
                    vector_format=VF_LIST_OF_COMPONENTS))

                for name, field in cell_data:
                    grid.add_celldata(DataArray(name, field,
                    vector_format=VF_LIST_OF_COMPONENTS))

                from os.path import exists
                path_to_file = pjoin("vis_files", file_name)
                if exists(path_to_file):
                   raise RuntimeError("output file '%s' already exists"
                   % path_to_file)

                outf = open(path_to_file, "w")
                AppendedDataXMLGenerator(compressor)(grid).write(outf)
                outf.close()

    queue.finish()
    print 'time spent is', time.time()-start_time, 'seconds'

    u_1_soln = u_1_gpu.get()
    u_2_soln = u_2_gpu.get()
    u_3_soln = u_3_gpu.get()
    #print u_1_soln
    #print u_2_soln
    #calculate error
    if ii != start_size: 
        errinf1, errinf2, errinf3, err11, err12, err13, err21, err22, err23 = err(u_1_soln, u_2_soln, u_3_soln, u_1_o, u_2_o, u_3_o)

    #errinf1, errinf2, errinf3, err11, err12, err13, err21, err22, err23 = err_ex(clock_max, u_1_soln, u_2_soln, u_3_soln)
        print 'u Errinf1 is', errinf1, '\n u Errinf2 is', errinf2, '\n u Errinf3 is', errinf3
        print 'u Err11 is', err11, '\n u Err12 is', err12, '\n u Err13 is', err13
        print 'u Err21 is', err21, '\n u Err22 is', err22, '\n u Err23 is', err23

    u_1_o = u_1_soln
    u_2_o = u_2_soln
    u_3_o = u_3_soln
